Instruction:
Write a Python 3 script to
run given callable against given table and given column in activity table.

Response:
def alter_column(conn, table, column_name, func, schema=None):
    """
    Run given callable against given table and given column in activity table
    jsonb data columns. This function is useful when you want to reflect type
    changes in your schema to activity table.

    In the following example we change the data type of User's age column from
    string to integer.

    ::

        from alembic import op
        from postgresql_audit import alter_column

        def upgrade():
            op.alter_column(
                'user',
                'age',
                type_=sa.Integer
            )

            alter_column(
                op,
                'user',
                'age',
                lambda value, activity_table: sa.cast(value, sa.Integer)
            )

    :param conn:
        An object that is able to execute SQL (either SQLAlchemy Connection,
        Engine or Alembic Operations object)
    :param table:
        The table to run the column name changes against
    :param column_name:
        Name of the column to run callable against
    :param func:
        A callable to run against specific column in activity table jsonb data
        columns. The callable should take two parameters the jsonb value
        corresponding to given column_name and activity table object.
    :param schema:
        Optional name of schema to use.
    """
    activity_table = get_activity_table(schema=schema)
    query = (
        activity_table
        .update()
        .values(
            old_data=(
                activity_table.c.old_data +
                sa.cast(sa.func.json_build_object(
                    column_name,
                    func(
                        activity_table.c.old_data[column_name],
                        activity_table
                    )
                ), JSONB)
            ),
            changed_data=(
                activity_table.c.changed_data +
                sa.cast(sa.func.json_build_object(
                    column_name,
                    func(
                        activity_table.c.changed_data[column_name],
                        activity_table
                    )
                ), JSONB)
            )
        )
        .where(activity_table.c.table_name == table)
    )
    return conn.execute(query)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def change_column_name(
    conn,
    table,
    old_column_name,
    new_column_name,
    schema=None
):
    """
    Changes given `activity` jsonb data column key. This function is useful
    when you want to reflect column name changes to activity table.

    ::

        from alembic import op
        from postgresql_audit import change_column_name

        def upgrade():
            op.alter_column(
                'my_table',
                'my_column',
                new_column_name='some_column'
            )

            change_column_name(op, 'my_table', 'my_column', 'some_column')

    :param conn:
        An object that is able to execute SQL (either SQLAlchemy Connection,
        Engine or Alembic Operations object)
    :param table:
        The table to run the column name changes against
    :param old_column_name:
        Name of the column to change
    :param new_column_name:
        New colum name
    :param schema:
        Optional name of schema to use.
    """
    activity_table = get_activity_table(schema=schema)
    query = (
        activity_table
        .update()
        .values(
            old_data=jsonb_change_key_name(
                activity_table.c.old_data,
                old_column_name,
                new_column_name
            ),
            changed_data=jsonb_change_key_name(
                activity_table.c.changed_data,
                old_column_name,
                new_column_name
            )
        )
        .where(activity_table.c.table_name == table)
    )
    return conn.execute(query)

Response: Changes the name of a column in an existing activity table.


Instruction:
Can you create a Python 3 function that
adds given column to the activity table jsonb data columns.

Response:
def add_column(conn, table, column_name, default_value=None, schema=None):
    """
    Adds given column to `activity` table jsonb data columns.

    In the following example we reflect the changes made to our schema to
    activity table.

    ::

        import sqlalchemy as sa
        from alembic import op
        from postgresql_audit import add_column

        def upgrade():
            op.add_column('article', sa.Column('created_at', sa.DateTime()))
            add_column(op, 'article', 'created_at')

    :param conn:
        An object that is able to execute SQL (either SQLAlchemy Connection,
        Engine or Alembic Operations object)
    :param table:
        The table to remove the column from
    :param column_name:
        Name of the column to add
    :param default_value:
        The default value of the column
    :param schema:
        Optional name of schema to use.
    """
    activity_table = get_activity_table(schema=schema)
    data = {column_name: default_value}
    query = (
        activity_table
        .update()
        .values(
            old_data=sa.case(
                [
                    (
                        sa.cast(activity_table.c.old_data, sa.Text) != '{}',
                        activity_table.c.old_data + data
                    ),
                ],
                else_=sa.cast({}, JSONB)
            ),
            changed_data=sa.case(
                [
                    (
                        sa.and_(
                            sa.cast(
                                activity_table.c.changed_data,
                                sa.Text
                            ) != '{}',
                            activity_table.c.verb != 'update'
                        ),
                        activity_table.c.changed_data + data
                    )
                ],
                else_=activity_table.c.changed_data
            ),
        )
        .where(activity_table.c.table_name == table)
    )
    return conn.execute(query)


Instruction:
Implement a function in Python 3 to
remove given column from the activity jsonb data table.

Response:
def remove_column(conn, table, column_name, schema=None):
    """
    Removes given `activity` jsonb data column key. This function is useful
    when you are doing schema changes that require removing a column.

    Let's say you've been using PostgreSQL-Audit for a while for a table called
    article. Now you want to remove one audited column called 'created_at' from
    this table.

    ::

        from alembic import op
        from postgresql_audit import remove_column

        def upgrade():
            op.remove_column('article', 'created_at')
            remove_column(op, 'article', 'created_at')

    :param conn:
        An object that is able to execute SQL (either SQLAlchemy Connection,
        Engine or Alembic Operations object)
    :param table:
        The table to remove the column from
    :param column_name:
        Name of the column to remove
    :param schema:
        Optional name of schema to use.
    """
    activity_table = get_activity_table(schema=schema)
    remove = sa.cast(column_name, sa.Text)
    query = (
        activity_table
        .update()
        .values(
            old_data=activity_table.c.old_data - remove,
            changed_data=activity_table.c.changed_data - remove,
        )
        .where(activity_table.c.table_name == table)
    )
    return conn.execute(query)


Instruction:
Can you generate a brief explanation for the following Python 3 code
def rename_table(conn, old_table_name, new_table_name, schema=None):
    activity_table = get_activity_table(schema=schema)
    query = (
        activity_table
        .update()
        .values(table_name=new_table_name)
        .where(activity_table.c.table_name == old_table_name)
    )
    return conn.execute(query)

Response: Renames given table in activity table.


Instruction:
Implement a Python 3 function for
collecting versioned class and add it to pending_classes list. :mapper mapper: SQLAlchemy mapper object :cls cls: SQLAlchemy declarative class

Response:
def instrument_versioned_classes(self, mapper, cls):
        """
        Collect versioned class and add it to pending_classes list.

        :mapper mapper: SQLAlchemy mapper object
        :cls cls: SQLAlchemy declarative class
        """
        if hasattr(cls, '__versioned__') and cls not in self.pending_classes:
            self.pending_classes.add(cls)


Instruction:
How would you code a function in Python 3 to
configure all versioned classes that were collected during instrumentation process.

Response:
def configure_versioned_classes(self):
        """
        Configures all versioned classes that were collected during
        instrumentation process.
        """
        for cls in self.pending_classes:
            self.audit_table(cls.__table__, cls.__versioned__.get('exclude'))
        assign_actor(self.base, self.transaction_cls, self.actor_cls)


Instruction:
Write a Python 3 function that can
get a citation via the command line using a PubMed ID or PubMed URL

Response:
def pubmed_citation(args=sys.argv[1:], out=sys.stdout):
    """Get a citation via the command line using a PubMed ID or PubMed URL"""

    parser = argparse.ArgumentParser(
        description='Get a citation using a PubMed ID or PubMed URL')
    parser.add_argument('query', help='PubMed ID or PubMed URL')
    parser.add_argument(
        '-m', '--mini', action='store_true', help='get mini citation')
    parser.add_argument(
        '-e', '--email', action='store', help='set user email', default='')

    args = parser.parse_args(args=args)

    lookup = PubMedLookup(args.query, args.email)
    publication = Publication(lookup, resolve_doi=False)

    if args.mini:
        out.write(publication.cite_mini() + '\n')
    else:
        out.write(publication.cite() + '\n')


Instruction:
Make a summary of the following Python 3 code
def pubmed_url(args=sys.argv[1:], resolve_doi=True, out=sys.stdout):

    parser = argparse.ArgumentParser(
        description='Get a publication URL using a PubMed ID or PubMed URL')
    parser.add_argument('query', help='PubMed ID or PubMed URL')
    parser.add_argument(
        '-d', '--doi', action='store_false', help='get DOI URL')
    parser.add_argument(
        '-e', '--email', action='store', help='set user email', default='')

    args = parser.parse_args(args=args)

    lookup = PubMedLookup(args.query, args.email)
    publication = Publication(lookup, resolve_doi=args.doi)

    out.write(publication.url + '\n')

Response: Get a publication URL via the command line using a PubMed ID or PubMed URL


Instruction:
Can you implement a function in Python 3 that
returns a truncated author list followed by et al.

Response:
def authors_et_al(self, max_authors=5):
        """
        Return string with a truncated author list followed by 'et al.'
        """
        author_list = self._author_list
        if len(author_list) <= max_authors:
            authors_et_al = self.authors
        else:
            authors_et_al = ", ".join(
                self._author_list[:max_authors]) + ", et al."
        return authors_et_al


Instruction:
Can you generate the documentation for the following Python 3 function
def cite(self, max_authors=5):
        citation_data = {
            'title': self.title,
            'authors': self.authors_et_al(max_authors),
            'year': self.year,
            'journal': self.journal,
            'volume': self.volume,
            'issue': self.issue,
            'pages': self.pages,
        }
        citation = "{authors} ({year}). {title} {journal}".format(
            **citation_data)

        if self.volume and self.issue and self.pages:
            citation += " {volume}({issue}): {pages}.".format(**citation_data)
        elif self.volume and self.issue:
            citation += " {volume}({issue}).".format(**citation_data)
        elif self.volume and self.pages:
            citation += " {volume}: {pages}.".format(**citation_data)
        elif self.volume:
            citation += " {volume}.".format(**citation_data)
        elif self.pages:
            citation += " {pages}.".format(**citation_data)
        else:
            citation += "."

        return citation

Response: Return a string with a citation for the record.


Instruction:
Given the following Python 3 function, write the documentation
def cite_mini(self):
        citation_data = [self.first_author]

        if len(self._author_list) > 1:
            citation_data.append(self.last_author)

        citation_data.extend([self.year, self.journal])

        return " - ".join(citation_data)

Response: Return a string with a citation for the record formatted as :


Instruction:
Given the following Python 3 function, write the documentation
def parse_abstract(xml_dict):
        key_path = ['PubmedArticleSet', 'PubmedArticle', 'MedlineCitation',
                    'Article', 'Abstract', 'AbstractText']
        abstract_xml = reduce(dict.get, key_path, xml_dict)

        abstract_paragraphs = []

        if isinstance(abstract_xml, str):
            abstract_paragraphs.append(abstract_xml)

        elif isinstance(abstract_xml, dict):
            abstract_text = abstract_xml.get('#text')
            try:
                abstract_label = abstract_xml['@Label']
            except KeyError:
                abstract_paragraphs.append(abstract_text)
            else:
                abstract_paragraphs.append(
                    "{}: {}".format(abstract_label, abstract_text))

        elif isinstance(abstract_xml, list):
            for abstract_section in abstract_xml:
                try:
                    abstract_text = abstract_section['#text']
                except KeyError:
                    abstract_text = abstract_section

                try:
                    abstract_label = abstract_section['@Label']
                except KeyError:
                    abstract_paragraphs.append(abstract_text)
                else:
                    abstract_paragraphs.append(
                        "{}: {}".format(abstract_label, abstract_text))

        else:
            raise RuntimeError("Error parsing abstract.")

        return "\n\n".join(abstract_paragraphs)

Response: Parse PubMed XML dictionary to retrieve abstract.


Instruction:
Can you tell what is the following Python 3 function doing
def get_pubmed_xml(self):
        url = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/' \
              'efetch.fcgi?db=pubmed&rettype=abstract&id={}' \
              .format(self.pmid)

        try:
            response = urlopen(url)
        except URLError:
            xml_dict = ''
        else:
            xml = response.read().decode()
            xml_dict = xmltodict.parse(xml)

        return xml_dict

Response: Get PubMed metadata in XML form.


Instruction:
Explain what the following Python 3 code does
def set_abstract(self, xml_dict):
        if self.record.get('HasAbstract') == 1 and xml_dict:
            self.abstract = self.parse_abstract(xml_dict)
        else:
            self.abstract = ''

Response: Set the abstract attribute of the object.


Instruction:
How would you code a function in Python 3 to
set article URL based on where the DOI points.

Response:
def set_article_url(self, resolve_doi=True):
        """
        If record has a DOI, set article URL based on where the DOI points.
        """
        if 'DOI' in self.record:
            doi_url = "/".join(['http://dx.doi.org', self.record['DOI']])

            if resolve_doi:
                try:
                    response = urlopen(doi_url)
                except URLError:
                    self.url = ''
                else:
                    self.url = response.geturl()
            else:
                self.url = doi_url

        else:
            self.url = ''


Instruction:
Can you generate a brief explanation for the following Python 3 code
def set_pub_year_month_day(self, xml_dict):
        key_path = ['PubmedArticleSet', 'PubmedArticle', 'MedlineCitation',
                    'Article', 'Journal', 'JournalIssue', 'PubDate']
        pubdate_xml = reduce(dict.get, key_path, xml_dict)

        if isinstance(pubdate_xml, dict):
            self.year = pubdate_xml.get('Year')
            month_short = pubdate_xml.get('Month')
            self.day = pubdate_xml.get('Day')

            try:
                self.month = datetime.datetime.strptime(
                    month_short, "%b").month
            except (ValueError, TypeError):
                self.month = ''

        else:
            self.year = ''
            self.month = ''
            self.day = ''

Response: Set publication year month day from PubMed s XML data


Instruction:
How would you explain what the following Python 3 function does
def parse_pubmed_url(pubmed_url):
        parse_result = urlparse(pubmed_url)
        pattern = re.compile(r'^/pubmed/(\d+)$')
        pmid = pattern.match(parse_result.path).group(1)
        return pmid

Response: Get PubMed ID from PubMed URL.


Instruction:
Make a summary of the following Python 3 code
def get_pubmed_record(pmid):
        handle = Entrez.esummary(db="pubmed", id=pmid)
        record = Entrez.read(handle)
        return record

Response: Get PubMed record from PubMed ID.


Instruction:
How would you code a function in Python 3 to
initialize the internal state of the object.

Response:
def _initialize(self, register_value_map=None, memory_value_map=None, default_value=None):
        """ Sets the wire, register, and memory values to default or as specified.

        :param register_value_map: is a map of {Register: value}.
        :param memory_value_map: is a map of maps {Memory: {address: Value}}.
        :param default_value: is the value that all unspecified registers and memories will
         default to. If no default_value is specified, it will use the value stored in the
         object (default to 0)
        """

        if default_value is None:
            default_value = self.default_value

        # set registers to their values
        reg_set = self.block.wirevector_subset(Register)
        if register_value_map is not None:
            for r in reg_set:
                self.value[r] = self.regvalue[r] = register_value_map.get(r, default_value)

        # set constants to their set values
        for w in self.block.wirevector_subset(Const):
            self.value[w] = w.val
            assert isinstance(w.val, numbers.Integral)  # for now

        # set memories to their passed values

        for mem_net in self.block.logic_subset('m@'):
            memid = mem_net.op_param[1].id
            if memid not in self.memvalue:
                self.memvalue[memid] = {}

        if memory_value_map is not None:
            for (mem, mem_map) in memory_value_map.items():
                if isinstance(mem, RomBlock):
                    raise PyrtlError('error, one or more of the memories in the map is a RomBlock')
                if isinstance(self.block, PostSynthBlock):
                    mem = self.block.mem_map[mem]  # pylint: disable=maybe-no-member
                self.memvalue[mem.id] = mem_map
                max_addr_val, max_bit_val = 2**mem.addrwidth, 2**mem.bitwidth
                for (addr, val) in mem_map.items():
                    if addr < 0 or addr >= max_addr_val:
                        raise PyrtlError('error, address %s in %s outside of bounds' %
                                         (str(addr), mem.name))
                    if val < 0 or val >= max_bit_val:
                        raise PyrtlError('error, %s at %s in %s outside of bounds' %
                                         (str(val), str(addr), mem.name))

        # set all other variables to default value
        for w in self.block.wirevector_set:
            if w not in self.value:
                self.value[w] = default_value

        self.ordered_nets = tuple((i for i in self.block))
        self.reg_update_nets = tuple((self.block.logic_subset('r')))
        self.mem_update_nets = tuple((self.block.logic_subset('@')))


Instruction:
Can you generate a brief explanation for the following Python 3 code
def step(self, provided_inputs):

        # Check that all Input have a corresponding provided_input
        input_set = self.block.wirevector_subset(Input)
        supplied_inputs = set()
        for i in provided_inputs:
            if isinstance(i, WireVector):
                name = i.name
            else:
                name = i
            sim_wire = self.block.wirevector_by_name[name]
            if sim_wire not in input_set:
                raise PyrtlError(
                    'step provided a value for input for "%s" which is '
                    'not a known input ' % name)
            if not isinstance(provided_inputs[i], numbers.Integral) or provided_inputs[i] < 0:
                raise PyrtlError(
                    'step provided an input "%s" which is not a valid '
                    'positive integer' % provided_inputs[i])
            if len(bin(provided_inputs[i]))-2 > sim_wire.bitwidth:
                raise PyrtlError(
                    'the bitwidth for "%s" is %d, but the provided input '
                    '%d requires %d bits to represent'
                    % (name, sim_wire.bitwidth,
                       provided_inputs[i], len(bin(provided_inputs[i]))-2))

            self.value[sim_wire] = provided_inputs[i]
            supplied_inputs.add(sim_wire)

        # Check that only inputs are specified, and set the values
        if input_set != supplied_inputs:
            for i in input_set.difference(supplied_inputs):
                raise PyrtlError('Input "%s" has no input value specified' % i.name)

        self.value.update(self.regvalue)  # apply register updates from previous step

        for net in self.ordered_nets:
            self._execute(net)

        # Do all of the mem operations based off the new values changed in _execute()
        for net in self.mem_update_nets:
            self._mem_update(net)

        # at the end of the step, record the values to the trace
        # print self.value # Helpful Debug Print
        if self.tracer is not None:
            self.tracer.add_step(self.value)

        # Do all of the reg updates based off of the new values
        for net in self.reg_update_nets:
            argval = self.value[net.args[0]]
            self.regvalue[net.dests[0]] = self._sanitize(argval, net.dests[0])

        # finally, if any of the rtl_assert assertions are failing then we should
        # raise the appropriate exceptions
        check_rtl_assertions(self)

Response: Take the simulation forward one cycle and set the value of the current value of the next wire.


Instruction:
Write a Python 3 function for
getting the value of a wirevector in the current simulation cycle.

Response:
def inspect(self, w):
        """ Get the value of a wirevector in the last simulation cycle.

        :param w: the name of the WireVector to inspect
            (passing in a WireVector instead of a name is deprecated)
        :return: value of w in the current step of simulation

        Will throw KeyError if w does not exist in the simulation.
        """
        wire = self.block.wirevector_by_name.get(w, w)
        return self.value[wire]


Instruction:
Write a Python 3 script for
executing the logic update rules for the given net.

Response:
def _execute(self, net):
        """Handle the combinational logic update rules for the given net.

        This function, along with edge_update, defined the semantics
        of the primitive ops. Function updates self.value accordingly.
        """
        if net.op in 'r@':
            return  # registers and memory write ports have no logic function
        elif net.op in self.simple_func:
            argvals = (self.value[arg] for arg in net.args)
            result = self.simple_func[net.op](*argvals)
        elif net.op == 'c':
            result = 0
            for arg in net.args:
                result = result << len(arg)
                result = result | self.value[arg]
        elif net.op == 's':
            result = 0
            source = self.value[net.args[0]]
            for b in net.op_param[::-1]:
                result = (result << 1) | (0x1 & (source >> b))
        elif net.op == 'm':
            # memories act async for reads
            memid = net.op_param[0]
            mem = net.op_param[1]
            read_addr = self.value[net.args[0]]
            if isinstance(mem, RomBlock):
                result = mem._get_read_data(read_addr)
            else:
                result = self.memvalue[memid].get(read_addr, self.default_value)
        else:
            raise PyrtlInternalError('error, unknown op type')

        self.value[net.dests[0]] = self._sanitize(result, net.dests[0])


Instruction:
Given the following Python 3 function, write the documentation
def _mem_update(self, net):
        if net.op != '@':
            raise PyrtlInternalError
        memid = net.op_param[0]
        write_addr = self.value[net.args[0]]
        write_val = self.value[net.args[1]]
        write_enable = self.value[net.args[2]]
        if write_enable:
            self.memvalue[memid][write_addr] = write_val

Response: Handle the mem update for the given net.


Instruction:
Here you have a function in Python 3, explain what it does
def step(self, provided_inputs):
        # validate_inputs
        for wire, value in provided_inputs.items():
            wire = self.block.get_wirevector_by_name(wire) if isinstance(wire, str) else wire
            if value > wire.bitmask or value < 0:
                raise PyrtlError("Wire {} has value {} which cannot be represented"
                                 " using its bitwidth".format(wire, value))

        # building the simulation data
        ins = {self._to_name(wire): value for wire, value in provided_inputs.items()}
        ins.update(self.regs)
        ins.update(self.mems)

        # propagate through logic
        self.regs, self.outs, mem_writes = self.sim_func(ins)

        for mem, addr, value in mem_writes:
            self.mems[mem][addr] = value

        # for tracer compatibility
        self.context = self.outs.copy()
        self.context.update(ins)  # also gets old register values
        if self.tracer is not None:
            self.tracer.add_fast_step(self)

        # check the rtl assertions
        check_rtl_assertions(self)

Response: Run the simulation for a cycle of the current block.


Instruction:
Create a Python 3 function for
getting the value of a wirevector in the last simulation cycle.

Response:
def inspect(self, w):
        """ Get the value of a wirevector in the last simulation cycle.

        :param w: the name of the WireVector to inspect
            (passing in a WireVector instead of a name is deprecated)
        :return: value of w in the current step of simulation

        Will throw KeyError if w is not being tracked in the simulation.
        """
        try:
            return self.context[self._to_name(w)]
        except AttributeError:
            raise PyrtlError("No context available. Please run a simulation step in "
                             "order to populate values for wires")


Instruction:
Write a Python 3 script to
get the values in a map during the current simulation cycle.

Response:
def inspect_mem(self, mem):
        """ Get the values in a map during the current simulation cycle.

        :param mem: the memory to inspect
        :return: {address: value}

        Note that this returns the current memory state. Modifying the dictonary
        will also modify the state in the simulator
        """
        if isinstance(mem, RomBlock):
            raise PyrtlError("ROM blocks are not stored in the simulation object")
        return self.mems[self._mem_varname(mem)]


Instruction:
Can you generate the documentation for the following Python 3 function
def _arg_varname(self, wire):
        if isinstance(wire, (Input, Register)):
            return 'd[' + repr(wire.name) + ']'  # passed in
        elif isinstance(wire, Const):
            return str(wire.val)  # hardcoded
        else:
            return self._varname(wire)

Response: Return the variable name for the passed in argument.


Instruction:
Explain what the following Python 3 code does
def _compiled(self):
        # Dev Notes:
        # Because of fast locals in functions in both CPython and PyPy, getting a
        # function to execute makes the code a few times faster than
        # just executing it in the global exec scope.
        prog = [self._prog_start]

        simple_func = {  # OPS
            'w': lambda x: x,
            'r': lambda x: x,
            '~': lambda x: '(~' + x + ')',
            '&': lambda l, r: '(' + l + '&' + r + ')',
            '|': lambda l, r: '(' + l + '|' + r + ')',
            '^': lambda l, r: '(' + l + '^' + r + ')',
            'n': lambda l, r: '(~(' + l + '&' + r + '))',
            '+': lambda l, r: '(' + l + '+' + r + ')',
            '-': lambda l, r: '(' + l + '-' + r + ')',
            '*': lambda l, r: '(' + l + '*' + r + ')',
            '<': lambda l, r: 'int(' + l + '<' + r + ')',
            '>': lambda l, r: 'int(' + l + '>' + r + ')',
            '=': lambda l, r: 'int(' + l + '==' + r + ')',
            'x': lambda sel, f, t: '({}) if ({}==0) else ({})'.format(f, sel, t),
        }

        def shift(value, direction, shift_amt):
            if shift_amt == 0:
                return value
            else:
                return '(%s %s %d)' % (value, direction, shift_amt)

        def make_split():
            if split_start_bit == 0:
                bit = '(%d & %s)' % ((1 << split_length) - 1, source)
            elif len(net.args[0]) - split_start_bit == split_length:
                bit = '(%s >> %d)' % (source, split_start_bit)
            else:
                bit = '(%d & (%s >> %d))' % ((1 << split_length) - 1, source, split_start_bit)
            return shift(bit, '<<', split_res_start_bit)

        for net in self.block:
            if net.op in simple_func:
                argvals = (self._arg_varname(arg) for arg in net.args)
                expr = simple_func[net.op](*argvals)
            elif net.op == 'c':
                expr = ''
                for i in range(len(net.args)):
                    if expr is not '':
                        expr += ' | '
                    shiftby = sum(len(j) for j in net.args[i+1:])
                    expr += shift(self._arg_varname(net.args[i]), '<<', shiftby)
            elif net.op == 's':
                source = self._arg_varname(net.args[0])
                expr = ''
                split_length = 0
                split_start_bit = -2
                split_res_start_bit = -1

                for i, b in enumerate(net.op_param):
                    if b != split_start_bit + split_length:
                        if split_start_bit >= 0:
                            # create a wire
                            expr += make_split() + '|'
                        split_length = 1
                        split_start_bit = b
                        split_res_start_bit = i
                    else:
                        split_length += 1
                expr += make_split()
            elif net.op == 'm':
                read_addr = self._arg_varname(net.args[0])
                mem = net.op_param[1]
                if isinstance(net.op_param[1], RomBlock):
                    expr = 'd["%s"]._get_read_data(%s)' % (self._mem_varname(mem), read_addr)
                else:  # memories act async for reads
                    expr = 'd["%s"].get(%s, %s)' % (self._mem_varname(mem),
                                                    read_addr, self.default_value)
            elif net.op == '@':
                mem = self._mem_varname(net.op_param[1])
                write_addr, write_val, write_enable = (self._arg_varname(a) for a in net.args)
                prog.append('    if {}:'.format(write_enable))
                prog.append('        mem_ws.append(("{}", {}, {}))'
                            .format(mem, write_addr, write_val))
                continue  # memwrites are special
            else:
                raise PyrtlError('FastSimulation cannot handle primitive "%s"' % net.op)

            # prog.append('    #  ' + str(net))
            result = self._dest_varname(net.dests[0])
            if len(net.dests[0]) == self._no_mask_bitwidth[net.op](net):
                prog.append("    %s = %s" % (result, expr))
            else:
                mask = str(net.dests[0].bitmask)
                prog.append('    %s = %s & %s' % (result, mask, expr))

        # add traced wires to dict
        if self.tracer is not None:
            for wire_name in self.tracer.trace:
                wire = self.block.wirevector_by_name[wire_name]
                if not isinstance(wire, (Input, Const, Register, Output)):
                    v_wire_name = self._varname(wire)
                    prog.append('    outs["%s"] = %s' % (wire_name, v_wire_name))

        prog.append("    return regs, outs, mem_ws")
        return '\n'.join(prog)

Response:
Return a string of the self. block compiled to a block of
         code that can be execed to get a function to execute


Instruction:
Explain what the following Python 3 code does
def _render_val_with_prev(self, w, n, current_val, symbol_len):
        sl = symbol_len-1
        if len(w) > 1:
            out = self._revstart
            if current_val != self.prior_val:
                out += self._x + hex(current_val).rstrip('L').ljust(sl)[:sl]
            elif n == 0:
                out += hex(current_val).rstrip('L').ljust(symbol_len)[:symbol_len]
            else:
                out += ' '*symbol_len
            out += self._revstop
        else:
            pretty_map = {
                (0, 0): self._low + self._low * sl,
                (0, 1): self._up + self._high * sl,
                (1, 0): self._down + self._low * sl,
                (1, 1): self._high + self._high * sl,
            }
            out = pretty_map[(self.prior_val, current_val)]
        return out

Response: Render the value of a given key in a waveform.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def add_step(self, value_map):
        if len(self.trace) == 0:
            raise PyrtlError('error, simulation trace needs at least 1 signal to track '
                             '(by default, unnamed signals are not traced -- try either passing '
                             'a name to a WireVector or setting a "wirevector_subset" option)')
        for wire in self.trace:
            tracelist = self.trace[wire]
            wirevec = self._wires[wire]
            tracelist.append(value_map[wirevec])

Response: Add the values in value_map to the end of the trace.


Instruction:
Here you have a function in Python 3, explain what it does
def add_fast_step(self, fastsim):
        for wire_name in self.trace:
            self.trace[wire_name].append(fastsim.context[wire_name])

Response: Add the fastsim context to the trace.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def print_trace(self, file=sys.stdout, base=10, compact=False):
        if len(self.trace) == 0:
            raise PyrtlError('error, cannot print an empty trace')
        if base not in (2, 8, 10, 16):
            raise PyrtlError('please choose a valid base (2,8,10,16)')

        basekey = {2: 'b', 8: 'o', 10: 'd', 16: 'x'}[base]
        ident_len = max(len(w) for w in self.trace)

        if compact:
            for w in sorted(self.trace, key=_trace_sort_key):
                vals = ''.join('{0:{1}}'.format(x, basekey) for x in self.trace[w])
                file.write(w.rjust(ident_len) + ' ' + vals + '\n')
        else:
            maxlenval = max(len('{0:{1}}'.format(x, basekey))
                            for w in self.trace for x in self.trace[w])
            file.write(' ' * (ident_len - 3) + "--- Values in base %d ---\n" % base)
            for w in sorted(self.trace, key=_trace_sort_key):
                vals = ' '.join('{0:>{1}{2}}'.format(x, maxlenval, basekey) for x in self.trace[w])
                file.write(w.ljust(ident_len + 1) + vals + '\n')

        file.flush()

Response: Prints a list of wires and their current values.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def print_vcd(self, file=sys.stdout, include_clock=False):
        # dump header info
        # file_timestamp = time.strftime("%a, %d %b %Y %H:%M:%S (UTC/GMT)", time.gmtime())
        # print >>file, " ".join(["$date", file_timestamp, "$end"])
        self.internal_names = _VerilogSanitizer('_vcd_tmp_')
        for wire in self.wires_to_track:
            self.internal_names.make_valid_string(wire.name)

        def _varname(wireName):
            """ Converts WireVector names to internal names """
            return self.internal_names[wireName]

        print(' '.join(['$timescale', '1ns', '$end']), file=file)
        print(' '.join(['$scope', 'module logic', '$end']), file=file)

        def print_trace_strs(time):
            for wn in sorted(self.trace, key=_trace_sort_key):
                print(' '.join([str(bin(self.trace[wn][time]))[1:], _varname(wn)]), file=file)

        # dump variables
        if include_clock:
            print(' '.join(['$var', 'wire', '1', 'clk', 'clk', '$end']), file=file)
        for wn in sorted(self.trace, key=_trace_sort_key):
            print(' '.join(['$var', 'wire', str(self._wires[wn].bitwidth),
                            _varname(wn), _varname(wn), '$end']), file=file)
        print(' '.join(['$upscope', '$end']), file=file)
        print(' '.join(['$enddefinitions', '$end']), file=file)
        print(' '.join(['$dumpvars']), file=file)
        print_trace_strs(0)
        print(' '.join(['$end']), file=file)

        # dump values
        endtime = max([len(self.trace[w]) for w in self.trace])
        for timestamp in range(endtime):
            print(''.join(['#', str(timestamp*10)]), file=file)
            print_trace_strs(timestamp)
            if include_clock:
                print('b1 clk', file=file)
                print('', file=file)
                print(''.join(['#', str(timestamp*10+5)]), file=file)
                print('b0 clk', file=file)
            print('', file=file)
        print(''.join(['#', str(endtime*10)]), file=file)
        file.flush()

Response: Prints out the current trace as a VCD dump.


Instruction:
Make a summary of the following Python 3 code
def render_trace(
            self, trace_list=None, file=sys.stdout, render_cls=default_renderer(),
            symbol_len=5, segment_size=5, segment_delim=' ', extra_line=True):

        """ Render the trace to a file using unicode and ASCII escape sequences.

        :param trace_list: A list of signals to be output in the specified order.
        :param file: The place to write output, default to stdout.
        :param render_cls: A class that translates traces into output bytes.
        :param symbol_len: The "length" of each rendered cycle in characters.
        :param segment_size: Traces are broken in the segments of this number of cycles.
        :param segment_delim: The character to be output between segments.
        :param extra_line: A Boolean to determin if we should print a blank line between signals.

        The resulting output can be viewed directly on the terminal or looked
        at with "more" or "less -R" which both should handle the ASCII escape
        sequences used in rendering. render_trace takes the following optional
        arguments.
        """
        if _currently_in_ipython():
            from IPython.display import display, HTML, Javascript  # pylint: disable=import-error
            from .inputoutput import trace_to_html
            htmlstring = trace_to_html(self, trace_list=trace_list, sortkey=_trace_sort_key)
            html_elem = HTML(htmlstring)
            display(html_elem)
            # print(htmlstring)
            js_stuff = """
            $.when(
            $.getScript("https://cdnjs.cloudflare.com/ajax/libs/wavedrom/1.6.2/skins/default.js"),
            $.getScript("https://cdnjs.cloudflare.com/ajax/libs/wavedrom/1.6.2/wavedrom.min.js"),
            $.Deferred(function( deferred ){
                $( deferred.resolve );
            })).done(function(){
                WaveDrom.ProcessAll();
            });"""
            display(Javascript(js_stuff))
        else:
            self.render_trace_to_text(
                trace_list=trace_list, file=file, render_cls=render_cls,
                symbol_len=symbol_len, segment_size=segment_size,
                segment_delim=segment_delim, extra_line=extra_line)

Response: Render the current signal to a file.


Instruction:
Can you create a Python 3 function that
returns the value in the first wire for which the select bit is 1.

Response:
def prioritized_mux(selects, vals):
    """
    Returns the value in the first wire for which its select bit is 1

    :param [WireVector] selects: a list of WireVectors signaling whether
        a wire should be chosen
    :param [WireVector] vals: values to return when the corresponding select
        value is 1
    :return: WireVector

    If none of the items are high, the last val is returned
    """
    if len(selects) != len(vals):
        raise pyrtl.PyrtlError("Number of select and val signals must match")
    if len(vals) == 0:
        raise pyrtl.PyrtlError("Must have a signal to mux")
    if len(vals) == 1:
        return vals[0]
    else:
        half = len(vals) // 2
        return pyrtl.select(pyrtl.rtl_any(*selects[:half]),
                            truecase=prioritized_mux(selects[:half], vals[:half]),
                            falsecase=prioritized_mux(selects[half:], vals[half:]))


Instruction:
Can you generate a brief explanation for the following Python 3 code
def _sparse_mux(sel, vals):
    items = list(vals.values())
    if len(vals) <= 1:
        if len(vals) == 0:
            raise pyrtl.PyrtlError("Needs at least one parameter for val")
        return items[0]

    if len(sel) == 1:
        try:
            false_result = vals[0]
            true_result = vals[1]
        except KeyError:
            raise pyrtl.PyrtlError("Failed to retrieve values for smartmux. "
                                   "The length of sel might be wrong")
    else:
        half = 2**(len(sel) - 1)

        first_dict = {indx: wire for indx, wire in vals.items() if indx < half}
        second_dict = {indx-half: wire for indx, wire in vals.items() if indx >= half}
        if not len(first_dict):
            return sparse_mux(sel[:-1], second_dict)
        if not len(second_dict):
            return sparse_mux(sel[:-1], first_dict)

        false_result = sparse_mux(sel[:-1], first_dict)
        true_result = sparse_mux(sel[:-1], second_dict)
    if _is_equivelent(false_result, true_result):
        return true_result
    return pyrtl.select(sel[-1], falsecase=false_result, truecase=true_result)

Response: Returns a sparse mux that avoids instantiating unnecessary mux_2s when possible.


Instruction:
Here you have a function in Python 3, explain what it does
def finalize(self):
        self._check_finalized()
        self._final = True

        for dest_w, values in self.dest_instrs_info.items():
            mux_vals = dict(zip(self.instructions, values))
            dest_w <<= sparse_mux(self.signal_wire, mux_vals)

Response: Finalizes the internal state of the object.


Instruction:
Implement a Python 3 function for
logging all actions to console as they are dispatched

Response:
def log_middleware(store):
    """log all actions to console as they are dispatched"""
    def wrapper(next_):
        def log_dispatch(action):
            print('Dispatch Action:', action)
            return next_(action)
        return log_dispatch
    return wrapper


Instruction:
Can you write a function in Python 3 where it
gets the latest value of the wire given if possible.

Response:
def inspect(self, w):
        """Get the latest value of the wire given, if possible."""
        if isinstance(w, WireVector):
            w = w.name
        try:
            vals = self.tracer.trace[w]
        except KeyError:
            pass
        else:
            if not vals:
                raise PyrtlError('No context available. Please run a simulation step')
            return vals[-1]
        raise PyrtlError('CompiledSimulation does not support inspecting internal WireVectors')


Instruction:
Explain what the following Python 3 code does
def run(self, inputs):
        steps = len(inputs)
        # create i/o arrays of the appropriate length
        ibuf_type = ctypes.c_uint64*(steps*self._ibufsz)
        obuf_type = ctypes.c_uint64*(steps*self._obufsz)
        ibuf = ibuf_type()
        obuf = obuf_type()
        # these array will be passed to _crun
        self._crun.argtypes = [ctypes.c_uint64, ibuf_type, obuf_type]

        # build the input array
        for n, inmap in enumerate(inputs):
            for w in inmap:
                if isinstance(w, WireVector):
                    name = w.name
                else:
                    name = w
                start, count = self._inputpos[name]
                start += n*self._ibufsz
                val = inmap[w]
                if val >= 1 << self._inputbw[name]:
                    raise PyrtlError(
                        'Wire {} has value {} which cannot be represented '
                        'using its bitwidth'.format(name, val))
                # pack input
                for pos in range(start, start+count):
                    ibuf[pos] = val & ((1 << 64)-1)
                    val >>= 64

        # run the simulation
        self._crun(steps, ibuf, obuf)

        # save traced wires
        for name in self.tracer.trace:
            rname = self._probe_mapping.get(name, name)
            if rname in self._outputpos:
                start, count = self._outputpos[rname]
                buf, sz = obuf, self._obufsz
            elif rname in self._inputpos:
                start, count = self._inputpos[rname]
                buf, sz = ibuf, self._ibufsz
            else:
                raise PyrtlInternalError('Untraceable wire in tracer')
            res = []
            for n in range(steps):
                val = 0
                # unpack output
                for pos in reversed(range(start, start+count)):
                    val <<= 64
                    val |= buf[pos]
                res.append(val)
                start += sz
            self.tracer.trace[name].extend(res)

Response:
Run many steps of the simulation.

        The argument is a list of input mappings for each step,
        and its length is the number of steps to be executed.


Instruction:
Can you create a Python 3 function that
checks if a given wv is traceable.

Response:
def _traceable(self, wv):
        """Check if wv is able to be traced

        If it is traceable due to a probe, record that probe in _probe_mapping.
        """
        if isinstance(wv, (Input, Output)):
            return True
        for net in self.block.logic:
            if net.op == 'w' and net.args[0].name == wv.name and isinstance(net.dests[0], Output):
                self._probe_mapping[wv.name] = net.dests[0].name
                return True
        return False


Instruction:
How would you code a function in Python 3 to
remove from the tracer those wires that CompiledSimulation cannot track.

Response:
def _remove_untraceable(self):
        """Remove from the tracer those wires that CompiledSimulation cannot track.

        Create _probe_mapping for wires only traceable via probes.
        """
        self._probe_mapping = {}
        wvs = {wv for wv in self.tracer.wires_to_track if self._traceable(wv)}
        self.tracer.wires_to_track = wvs
        self.tracer._wires = {wv.name: wv for wv in wvs}
        self.tracer.trace.__init__(wvs)


Instruction:
How would you implement a function in Python 3 that
creates a dynamically - linked library implementing the simulation logic.

Response:
def _create_dll(self):
        """Create a dynamically-linked library implementing the simulation logic."""
        self._dir = tempfile.mkdtemp()
        with open(path.join(self._dir, 'pyrtlsim.c'), 'w') as f:
            self._create_code(lambda s: f.write(s+'\n'))
        if platform.system() == 'Darwin':
            shared = '-dynamiclib'
        else:
            shared = '-shared'
        subprocess.check_call([
            'gcc', '-O0', '-march=native', '-std=c99', '-m64',
            shared, '-fPIC',
            path.join(self._dir, 'pyrtlsim.c'), '-o', path.join(self._dir, 'pyrtlsim.so'),
            ], shell=(platform.system() == 'Windows'))
        self._dll = ctypes.CDLL(path.join(self._dir, 'pyrtlsim.so'))
        self._crun = self._dll.sim_run_all
        self._crun.restype = None


Instruction:
Can you tell what is the following Python 3 function doing
def _makeini(self, w, v):
        pieces = []
        for n in range(self._limbs(w)):
            pieces.append(hex(v & ((1 << 64)-1)))
            v >>= 64
        return ','.join(pieces).join('{}')

Response: A function to make a string for a given wire with a given value.


Instruction:
Can you write a function in Python 3 where it
creates a bitmask. The value being masked is of width `res`. Limb number `pos` of `dest` is being assigned to.

Response:
def _makemask(self, dest, res, pos):
        """Create a bitmask.

        The value being masked is of width `res`.
        Limb number `pos` of `dest` is being assigned to.
        """
        if (res is None or dest.bitwidth < res) and 0 < (dest.bitwidth - 64*pos) < 64:
            return '&0x{:X}'.format((1 << (dest.bitwidth % 64))-1)
        return ''


Instruction:
Here you have a function in Python 3, explain what it does
def _getarglimb(self, arg, n):
        return '{vn}[{n}]'.format(vn=self.varname[arg], n=n) if arg.bitwidth > 64*n else '0'

Response: Get the nth limb of the given arg. Returns 0 when the wire does not have sufficient limbs.


Instruction:
Implement a Python 3 function for
creating a C variable name with the given prefix based on the name of obj.

Response:
def _clean_name(self, prefix, obj):
        """Create a C variable name with the given prefix based on the name of obj."""
        return '{}{}_{}'.format(prefix, self._uid(), ''.join(c for c in obj.name if c.isalnum()))


Instruction:
Implement a Python 3 function for
building a slow and small multiplication of two sets of wires.

Response:
def simple_mult(A, B, start):
    """ Builds a slow, small multiplier using the simple shift-and-add algorithm.
    Requires very small area (it uses only a single adder), but has long delay
    (worst case is len(A) cycles). start is a one-bit input to indicate inputs are ready.
    done is a one-bit output signal raised when the multiplication is finished.

    :param WireVector A, B: two input wires for the multiplication
    :returns: Register containing the product; the "done" signal

    """
    triv_result = _trivial_mult(A, B)
    if triv_result is not None:
        return triv_result, pyrtl.Const(1, 1)

    alen = len(A)
    blen = len(B)
    areg = pyrtl.Register(alen)
    breg = pyrtl.Register(blen + alen)
    accum = pyrtl.Register(blen + alen)
    done = (areg == 0)  # Multiplication is finished when a becomes 0

    # During multiplication, shift a right every cycle, b left every cycle
    with pyrtl.conditional_assignment:
        with start:  # initialization
            areg.next |= A
            breg.next |= B
            accum.next |= 0
        with ~done:  # don't run when there's no work to do
            areg.next |= areg[1:]  # right shift
            breg.next |= pyrtl.concat(breg, pyrtl.Const(0, 1))  # left shift
            a_0_val = areg[0].sign_extended(len(accum))

            # adds to accum only when LSB of areg is 1
            accum.next |= accum + (a_0_val & breg)

    return accum, done


Instruction:
Given the following Python 3 function, write the documentation
def _trivial_mult(A, B):
    if len(B) == 1:
        A, B = B, A  # so that we can reuse the code below :)
    if len(A) == 1:
        a_vals = A.sign_extended(len(B))

        # keep the wirevector len consistent
        return pyrtl.concat_list([a_vals & B, pyrtl.Const(0)])

Response: This function turns a multiplication into an And gate if one of the wires is a bitwidth of 1.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def complex_mult(A, B, shifts, start):

    alen = len(A)
    blen = len(B)
    areg = pyrtl.Register(alen)
    breg = pyrtl.Register(alen + blen)
    accum = pyrtl.Register(alen + blen)
    done = (areg == 0)  # Multiplication is finished when a becomes 0
    if (shifts > alen) or (shifts > blen):
        raise pyrtl.PyrtlError("shift is larger than one or both of the parameters A or B,"
                               "please choose smaller shift")

    # During multiplication, shift a right every cycle 'shift' times,
    # shift b left every cycle 'shift' times
    with pyrtl.conditional_assignment:
        with start:  # initialization
            areg.next |= A
            breg.next |= B
            accum.next |= 0

        with ~done:  # don't run when there's no work to do
            # "Multiply" shifted breg by LSB of areg by cond. adding
            areg.next |= libutils._shifted_reg_next(areg, 'r', shifts)  # right shift
            breg.next |= libutils._shifted_reg_next(breg, 'l', shifts)  # left shift
            accum.next |= accum + _one_cycle_mult(areg, breg, shifts)

    return accum, done

Response: Generates a shift - and - add multiplier that can shift and add multiple bits per clock cycle.


Instruction:
Can you tell what is the following Python 3 function doing
def _one_cycle_mult(areg, breg, rem_bits, sum_sf=0, curr_bit=0):
    if rem_bits == 0:
        return sum_sf
    else:
        a_curr_val = areg[curr_bit].sign_extended(len(breg))
        if curr_bit == 0:  # if no shift
            return(_one_cycle_mult(areg, breg, rem_bits-1,  # areg, breg, rem_bits
                                   sum_sf + (a_curr_val & breg),  # sum_sf
                                   curr_bit+1))  # curr_bit
        else:
            return _one_cycle_mult(
                areg, breg, rem_bits-1,  # areg, breg, rem_bits
                sum_sf + (a_curr_val &
                          pyrtl.concat(breg, pyrtl.Const(0, curr_bit))),  # sum_sf
                curr_bit+1  # curr_bit
            )

Response: This function multiplies the current bit in one cycle of the internal group.


Instruction:
Create a Python 3 function for
building a tree multiplier for inputs A and B using a Wallace or Dada Tree multiplier.

Response:
def tree_multiplier(A, B, reducer=adders.wallace_reducer, adder_func=adders.kogge_stone):
    """ Build an fast unclocked multiplier for inputs A and B using a Wallace or Dada Tree.

    :param WireVector A, B: two input wires for the multiplication
    :param function reducer: Reduce the tree using either a Dada recuder or a Wallace reducer
      determines whether it is a Wallace tree multiplier or a Dada tree multiplier
    :param function adder_func: an adder function that will be used to do the last addition
    :return WireVector: The multiplied result

    Delay is order logN, while area is order N^2.
    """

    """
    The two tree multipliers basically works by splitting the multiplication
    into a series of many additions, and it works by applying 'reductions'.
    """
    triv_res = _trivial_mult(A, B)
    if triv_res is not None:
        return triv_res

    bits_length = (len(A) + len(B))

    # create a list of lists, with slots for all the weights (bit-positions)
    bits = [[] for weight in range(bits_length)]

    # AND every bit of A with every bit of B (N^2 results) and store by "weight" (bit-position)
    for i, a in enumerate(A):
        for j, b in enumerate(B):
            bits[i + j].append(a & b)

    return reducer(bits, bits_length, adder_func)


Instruction:
Here you have a function in Python 3, explain what it does
def signed_tree_multiplier(A, B, reducer=adders.wallace_reducer, adder_func=adders.kogge_stone):
    if len(A) == 1 or len(B) == 1:
        raise pyrtl.PyrtlError("sign bit required, one or both wires too small")

    aneg, bneg = A[-1], B[-1]
    a = _twos_comp_conditional(A, aneg)
    b = _twos_comp_conditional(B, bneg)

    res = tree_multiplier(a[:-1], b[:-1]).zero_extended(len(A) + len(B))
    return _twos_comp_conditional(res, aneg ^ bneg)

Response: Same as tree_multiplier but uses two s - complement signed integers


Instruction:
How would you code a function in Python 3 to
return two s complement of wire with sign_bit == 1

Response:
def _twos_comp_conditional(orig_wire, sign_bit, bw=None):
    """Returns two's complement of wire (using bitwidth bw) if sign_bit == 1"""
    if bw is None:
        bw = len(orig_wire)
    new_wire = pyrtl.WireVector(bw)
    with pyrtl.conditional_assignment:
        with sign_bit:
            new_wire |= ~orig_wire + 1
        with pyrtl.otherwise:
            new_wire |= orig_wire
    return new_wire


Instruction:
Implement a Python 3 function for
generating efficient hardware for a*b+c. Multiplies two wirevectors together and adds a third wirevector to the multiplication result, all in one step. By doing it this way (instead of separately), one reduces both the area and the timing delay of the circuit. :param Bool signed: Currently not supported (will be added in the future) The default will likely be changed to True, so if you want the smallest set of wires in the future, specify this as False :param reducer: (advanced) The tree reducer to use :param adder_func: (advanced) The adder to use to add the two results at the end :return WireVector: The result WireVector

Response:
def fused_multiply_adder(mult_A, mult_B, add, signed=False, reducer=adders.wallace_reducer,
                         adder_func=adders.kogge_stone):
    """ Generate efficient hardware for a*b+c.

    Multiplies two wirevectors together and adds a third wirevector to the
    multiplication result, all in
    one step. By doing it this way (instead of separately), one reduces both
    the area and the timing delay of the circuit.

    :param Bool signed: Currently not supported (will be added in the future)
      The default will likely be changed to True, so if you want the smallest
      set of wires in the future, specify this as False
    :param reducer: (advanced) The tree reducer to use
    :param adder_func: (advanced) The adder to use to add the two results at the end
    :return WireVector: The result WireVector

    """

    # TODO: Specify the length of the result wirevector

    return generalized_fma(((mult_A, mult_B),), (add,), signed, reducer, adder_func)


Instruction:
Can you tell what is the following Python 3 function doing
def generalized_fma(mult_pairs, add_wires, signed=False, reducer=adders.wallace_reducer,
                    adder_func=adders.kogge_stone):
    """Generated an opimitized fused multiply adder.

    A generalized FMA unit that multiplies each pair of numbers in mult_pairs,
    then adds the resulting numbers and and the values of the add wires all
    together to form an answer. This is faster than separate adders and
    multipliers because you avoid unnecessary adder structures for intermediate
    representations.

    :param mult_pairs: Either None (if there are no pairs to multiply) or
      a list of pairs of wires to multiply:
      [(mult1_1, mult1_2), ...]
    :param add_wires: Either None (if there are no individual
      items to add other than the mult_pairs), or a list of wires for adding on
      top of the result of the pair multiplication.
    :param Bool signed: Currently not supported (will be added in the future)
      The default will likely be changed to True, so if you want the smallest
      set of wires in the future, specify this as False
    :param reducer: (advanced) The tree reducer to use
    :param adder_func: (advanced) The adder to use to add the two results at the end
    :return WireVector: The result WireVector

    """
    # first need to figure out the max length
    if mult_pairs:  # Need to deal with the case when it is empty
        mult_max = max(len(m[0]) + len(m[1]) - 1 for m in mult_pairs)
    else:
        mult_max = 0

    if add_wires:
        add_max = max(len(x) for x in add_wires)
    else:
        add_max = 0

    longest_wire_len = max(add_max, mult_max)
    bits = [[] for i in range(longest_wire_len)]

    for mult_a, mult_b in mult_pairs:
        for i, a in enumerate(mult_a):
            for j, b in enumerate(mult_b):
                bits[i + j].append(a & b)

    for wire in add_wires:
        for bit_loc, bit in enumerate(wire):
            bits[bit_loc].append(bit)

    import math
    result_bitwidth = (longest_wire_len +
                       int(math.ceil(math.log(len(add_wires) + len(mult_pairs), 2))))
    return reducer(bits, result_bitwidth, adder_func)

Response: This function generates a generalized FMA unit that multiplies each pair of numbers and adds the resulting numbers and values of the add wires at the end of the intermediate ArcGIS tree.


Instruction:
Can you create a Python 3 function that
maps nets to new sets of nets according to a custom function

Response:
def net_transform(transform_func, block=None, **kwargs):
    """
    Maps nets to new sets of nets according to a custom function

    :param transform_func:
        Function signature: func(orig_net (logicnet)) -> keep_orig_net (bool)
    :return:
    """
    block = working_block(block)
    with set_working_block(block, True):
        for net in block.logic.copy():
            keep_orig_net = transform_func(net, **kwargs)
            if not keep_orig_net:
                block.logic.remove(net)


Instruction:
Here you have a function in Python 3, explain what it does
def all_nets(transform_func):
    @functools.wraps(transform_func)
    def t_res(**kwargs):
        net_transform(transform_func, **kwargs)
    return t_res

Response: Decorator that wraps a net transform function and returns a new object that is passed to the next net transform function.


Instruction:
Create a Python 3 function for
mapping Wires to new sets of nets and wires according to a custom function :param transform_func: The function you want to run on all wires Function signature: func(orig_wire (WireVector)) -> src_wire, dst_wire src_wire is the src for the stuff you made in the transform func and dst_wire is the sink to indicate that the wire has not been changed, make src_wire and dst_wire both the original wire :param select_types: Type or Tuple of types of WireVectors to replace :param exclude_types: Type or Tuple of types of WireVectors to exclude from replacement :param block: The Block to replace wires on

Response:
def wire_transform(transform_func, select_types=WireVector,
                   exclude_types=(Input, Output, Register, Const), block=None):
    """
    Maps Wires to new sets of nets and wires according to a custom function

    :param transform_func: The function you want to run on all wires
        Function signature: func(orig_wire (WireVector)) -> src_wire, dst_wire
        src_wire is the src for the stuff you made in the transform func
        and dst_wire is the sink

        to indicate that the wire has not been changed, make src_wire and dst_wire both
        the original wire
    :param select_types: Type or Tuple of types of WireVectors to replace
    :param exclude_types: Type or Tuple of types of WireVectors to exclude from replacement
    :param block: The Block to replace wires on
    """
    block = working_block(block)
    for orig_wire in block.wirevector_subset(select_types, exclude_types):
        new_src, new_dst = transform_func(orig_wire)
        replace_wire(orig_wire, new_src, new_dst, block)


Instruction:
Here you have a function in Python 3, explain what it does
def replace_wires(wire_map, block=None):
    block = working_block(block)
    src_nets, dst_nets = block.net_connections(include_virtual_nodes=False)
    for old_w, new_w in wire_map.items():
        replace_wire_fast(old_w, new_w, new_w, src_nets, dst_nets, block)

Response: Quickly replace all wires in a block by new ones.


Instruction:
Given the following Python 3 function, write the documentation
def clone_wire(old_wire, name=None):
    if isinstance(old_wire, Const):
        return Const(old_wire.val, old_wire.bitwidth)
    else:
        if name is None:
            return old_wire.__class__(old_wire.bitwidth, name=old_wire.name)
        return old_wire.__class__(old_wire.bitwidth, name=name)

Response: Makes a copy of any existing wire


Instruction:
How would you code a function in Python 3 to
make a copy of an existing block

Response:
def copy_block(block=None, update_working_block=True):
    """
    Makes a copy of an existing block

    :param block: The block to clone. (defaults to the working block)
    :return: The resulting block
    """
    block_in = working_block(block)
    block_out, temp_wv_map = _clone_block_and_wires(block_in)
    mems = {}
    for net in block_in.logic:
        _copy_net(block_out, net, temp_wv_map, mems)
    block_out.mem_map = mems

    if update_working_block:
        set_working_block(block_out)
    return block_out


Instruction:
Can you generate the documentation for the following Python 3 function
def _clone_block_and_wires(block_in):
    block_in.sanity_check()  # make sure that everything is valid
    block_out = block_in.__class__()
    temp_wv_map = {}
    with set_working_block(block_out, no_sanity_check=True):
        for wirevector in block_in.wirevector_subset():
            new_wv = clone_wire(wirevector)
            temp_wv_map[wirevector] = new_wv

    return block_out, temp_wv_map

Response:
This function is a generic function to copy the WireVectors for another round of
    synthesis


Instruction:
Make a summary of the following Python 3 code
def _copy_net(block_out, net, temp_wv_net, mem_map):
    new_args = tuple(temp_wv_net[a_arg] for a_arg in net.args)
    new_dests = tuple(temp_wv_net[a_dest] for a_dest in net.dests)
    if net.op in "m@":  # special stuff for copying memories
        new_param = _get_new_block_mem_instance(net.op_param, mem_map, block_out)
    else:
        new_param = net.op_param

    new_net = LogicNet(net.op, new_param, args=new_args, dests=new_dests)
    block_out.add_net(new_net)

Response: This function copies a LogicNet to the block_out


Instruction:
How would you code a function in Python 3 to
get the instance of the memory in the new block that is associated with a memory in a old block that is not already in the mem_map.

Response:
def _get_new_block_mem_instance(op_param, mem_map, block_out):
    """ gets the instance of the memory in the new block that is
    associated with a memory in a old block
    """
    memid, old_mem = op_param
    if old_mem not in mem_map:
        new_mem = old_mem._make_copy(block_out)
        new_mem.id = old_mem.id
        mem_map[old_mem] = new_mem
    return memid, mem_map[old_mem]


Instruction:
Write a Python 3 script to
print useful information about a WireVector when in debug mode.

Response:
def probe(w, name=None):
    """ Print useful information about a WireVector when in debug mode.

    :param w: WireVector from which to get info
    :param name: optional name for probe (defaults to an autogenerated name)
    :return: original WireVector w

    Probe can be inserted into a existing design easily as it returns the
    original wire unmodified. For example ``y <<= x[0:3] + 4`` could be turned
    into ``y <<= probe(x)[0:3] + 4`` to give visibility into both the origin of
    ``x`` (including the line that WireVector was originally created) and
    the run-time values of ``x`` (which will be named and thus show up by
    default in a trace.  Likewise ``y <<= probe(x[0:3]) + 4``,
    ``y <<= probe(x[0:3] + 4)``, and ``probe(y) <<= x[0:3] + 4`` are all
    valid uses of `probe`.

    Note: `probe` does actually add a wire to the working block of w (which can
    confuse various post-processing transforms such as output to verilog).
    """
    if not isinstance(w, WireVector):
        raise PyrtlError('Only WireVectors can be probed')

    if name is None:
        name = '(%s: %s)' % (probeIndexer.make_valid_string(), w.name)
    print("Probe: " + name + ' ' + get_stack(w))

    p = Output(name=name)
    p <<= w  # late assigns len from w automatically
    return w


Instruction:
Explain what the following Python 3 code does
def rtl_assert(w, exp, block=None):
    block = working_block(block)

    if not isinstance(w, WireVector):
        raise PyrtlError('Only WireVectors can be asserted with rtl_assert')
    if len(w) != 1:
        raise PyrtlError('rtl_assert checks only a WireVector of bitwidth 1')
    if not isinstance(exp, Exception):
        raise PyrtlError('the second argument to rtl_assert must be an instance of Exception')
    if isinstance(exp, KeyError):
        raise PyrtlError('the second argument to rtl_assert cannot be a KeyError')
    if w not in block.wirevector_set:
        raise PyrtlError('assertion wire not part of the block to which it is being added')
    if w not in block.wirevector_set:
        raise PyrtlError('assertion not a known wirevector in the target block')

    if w in block.rtl_assert_dict:
        raise PyrtlInternalError('assertion conflicts with existing registered assertion')

    assert_wire = Output(bitwidth=1, name=assertIndexer.make_valid_string(), block=block)
    assert_wire <<= w
    block.rtl_assert_dict[assert_wire] = exp
    return assert_wire

Response: Add hardware assertions to be checked on the RTL design.


Instruction:
Implement a function in Python 3 to
check the values in sim to see if any registers assertions fail.

Response:
def check_rtl_assertions(sim):
    """ Checks the values in sim to see if any registers assertions fail.

    :param sim: Simulation in which to check the assertions
    :return: None
    """

    for (w, exp) in sim.block.rtl_assert_dict.items():
        try:
            value = sim.inspect(w)
            if not value:
                raise exp
        except KeyError:
            pass


Instruction:
How would you code a function in Python 3 to
allocate and return a list of WireVectors.

Response:
def wirevector_list(names, bitwidth=None, wvtype=WireVector):
    """ Allocate and return a list of WireVectors.

    :param names: Names for the WireVectors. Can be a list or single comma/space-separated string
    :param bitwidth: The desired bitwidth for the resulting WireVectors.
    :param WireVector wvtype: Which WireVector type to create.
    :return: List of WireVectors.

    Additionally, the ``names`` string can also contain an additional bitwidth specification
    separated by a ``/`` in the name. This cannot be used in combination with a ``bitwidth``
    value other than ``1``.

    Examples: ::

        wirevector_list(['name1', 'name2', 'name3'])
        wirevector_list('name1, name2, name3')
        wirevector_list('input1 input2 input3', bitwidth=8, wvtype=pyrtl.wire.Input)
        wirevector_list('output1, output2 output3', bitwidth=3, wvtype=pyrtl.wire.Output)
        wirevector_list('two_bits/2, four_bits/4, eight_bits/8')
        wirevector_list(['name1', 'name2', 'name3'], bitwidth=[2, 4, 8])

    """
    if isinstance(names, str):
        names = names.replace(',', ' ').split()

    if any('/' in name for name in names) and bitwidth is not None:
        raise PyrtlError('only one of optional "/" or bitwidth parameter allowed')

    if bitwidth is None:
        bitwidth = 1
    if isinstance(bitwidth, numbers.Integral):
        bitwidth = [bitwidth]*len(names)
    if len(bitwidth) != len(names):
        raise ValueError('number of names ' + str(len(names))
                         + ' should match number of bitwidths ' + str(len(bitwidth)))

    wirelist = []
    for fullname, bw in zip(names, bitwidth):
        try:
            name, bw = fullname.split('/')
        except ValueError:
            name, bw = fullname, bw
        wirelist.append(wvtype(bitwidth=int(bw), name=name))
    return wirelist


Instruction:
Write a Python 3 function that can
convert a python integer into a signed integer under twos complement.

Response:
def val_to_signed_integer(value, bitwidth):
    """ Return value as intrepreted as a signed integer under twos complement.

    :param value: a python integer holding the value to convert
    :param bitwidth: the length of the integer in bits to assume for conversion

    Given an unsigned integer (not a wirevector!) covert that to a signed
    integer.  This is useful for printing and interpreting values which are
    negative numbers in twos complement. ::

        val_to_signed_integer(0xff, 8) == -1
    """
    if isinstance(value, WireVector) or isinstance(bitwidth, WireVector):
        raise PyrtlError('inputs must not be wirevectors')
    if bitwidth < 1:
        raise PyrtlError('bitwidth must be a positive integer')

    neg_mask = 1 << (bitwidth - 1)
    neg_part = value & neg_mask

    pos_mask = neg_mask - 1
    pos_part = value & pos_mask

    return pos_part - neg_part


Instruction:
Can you create a Python 3 function that
converts a string containing a format string to an unsigned integer.

Response:
def formatted_str_to_val(data, format, enum_set=None):
    """ Return an unsigned integer representation of the data given format specified.

    :param data: a string holding the value to convert
    :param format: a string holding a format which will be used to convert the data string
    :param enum_set: an iterable of enums which are used as part of the converstion process

    Given a string (not a wirevector!) covert that to an unsigned integer ready for input
    to the simulation enviornment.  This helps deal with signed/unsigned numbers (simulation
    assumes the values have been converted via two's complement already), but it also takes
    hex, binary, and enum types as inputs.  It is easiest to see how it works with some
    examples. ::

        formatted_str_to_val('2', 's3') == 2  # 0b010
        formatted_str_to_val('-1', 's3') == 7  # 0b111
        formatted_str_to_val('101', 'b3') == 5
        formatted_str_to_val('5', 'u3') == 5
        formatted_str_to_val('-3', 's3') == 5
        formatted_str_to_val('a', 'x3') == 10
        class Ctl(Enum):
            ADD = 5
            SUB = 12
        formatted_str_to_val('ADD', 'e3/Ctl', [Ctl]) == 5
        formatted_str_to_val('SUB', 'e3/Ctl', [Ctl]) == 12

    """
    type = format[0]
    bitwidth = int(format[1:].split('/')[0])
    bitmask = (1 << bitwidth)-1
    if type == 's':
        rval = int(data) & bitmask
    elif type == 'x':
        rval = int(data, 16)
    elif type == 'b':
        rval = int(data, 2)
    elif type == 'u':
        rval = int(data)
        if rval < 0:
            raise PyrtlError('unsigned format requested, but negative value provided')
    elif type == 'e':
        enumname = format.split('/')[1]
        enum_inst_list = [e for e in enum_set if e.__name__ == enumname]
        if len(enum_inst_list) == 0:
            raise PyrtlError('enum "{}" not found in passed enum_set "{}"'
                             .format(enumname, enum_set))
        rval = getattr(enum_inst_list[0], data).value
    else:
        raise PyrtlError('unknown format type {}'.format(format))
    return rval


Instruction:
Can you implement a function in Python 3 that
converts the value in format to a string representation of the value in format specified.

Response:
def val_to_formatted_str(val, format, enum_set=None):
    """ Return a string representation of the value given format specified.

    :param val: a string holding an unsigned integer to convert
    :param format: a string holding a format which will be used to convert the data string
    :param enum_set: an iterable of enums which are used as part of the converstion process

    Given an unsigned integer (not a wirevector!) covert that to a strong ready for output
    to a human to interpret.  This helps deal with signed/unsigned numbers (simulation
    operates on values that have been converted via two's complement), but it also generates
    hex, binary, and enum types as outputs.  It is easiest to see how it works with some
    examples. ::

        formatted_str_to_val(2, 's3') == '2'
        formatted_str_to_val(7, 's3') == '-1'
        formatted_str_to_val(5, 'b3') == '101'
        formatted_str_to_val(5, 'u3') == '5'
        formatted_str_to_val(5, 's3') == '-3'
        formatted_str_to_val(10, 'x3') == 'a'
        class Ctl(Enum):
            ADD = 5
            SUB = 12
        formatted_str_to_val('ADD', 'e3/Ctl', [Ctl]) == 5
        formatted_str_to_val('SUB', 'e3/Ctl', [Ctl]) == 12

    """
    type = format[0]
    bitwidth = int(format[1:].split('/')[0])
    bitmask = (1 << bitwidth)-1
    if type == 's':
        rval = str(val_to_signed_integer(val, bitwidth))
    elif type == 'x':
        rval = hex(val)[2:]  # cuts off '0x' at the start
    elif type == 'b':
        rval = bin(val)[2:]  # cuts off '0b' at the start
    elif type == 'u':
        rval = str(int(val))  # nothing fancy
    elif type == 'e':
        enumname = format.split('/')[1]
        enum_inst_list = [e for e in enum_set if e.__name__ == enumname]
        if len(enum_inst_list) == 0:
            raise PyrtlError('enum "{}" not found in passed enum_set "{}"'
                             .format(enumname, enum_set))
        rval = enum_inst_list[0](val).name
    else:
        raise PyrtlError('unknown format type {}'.format(format))
    return rval


Instruction:
Can you create a Python 3 function that
returns whether a block has less nets than before

Response:
def shrank(self, block=None, percent_diff=0, abs_diff=1):
        """
        Returns whether a block has less nets than before

        :param Block block: block to check (if changed)
        :param Number percent_diff: percentage difference threshold
        :param int abs_diff: absolute difference threshold
        :return: boolean

        This function checks whether the change in the number of
        nets is greater than the percentage and absolute difference
        thresholds.
        """
        if block is None:
            block = self.block
        cur_nets = len(block.logic)
        net_goal = self.prev_nets * (1 - percent_diff) - abs_diff
        less_nets = (cur_nets <= net_goal)
        self.prev_nets = cur_nets
        return less_nets


Instruction:
Write a Python 3 function that can
create a Kogge - Stone adder given two WireVectors a and b.

Response:
def kogge_stone(a, b, cin=0):
    """
    Creates a Kogge-Stone adder given two inputs

    :param WireVector a, b: The two WireVectors to add up (bitwidths don't need to match)
    :param cin: An optimal carry in WireVector or value
    :return: a Wirevector representing the output of the adder

    The Kogge-Stone adder is a fast tree-based adder with O(log(n))
    propagation delay, useful for performance critical designs. However,
    it has O(n log(n)) area usage, and large fan out.
    """
    a, b = libutils.match_bitwidth(a, b)

    prop_orig = a ^ b
    prop_bits = [i for i in prop_orig]
    gen_bits = [i for i in a & b]
    prop_dist = 1

    # creation of the carry calculation
    while prop_dist < len(a):
        for i in reversed(range(prop_dist, len(a))):
            prop_old = prop_bits[i]
            gen_bits[i] = gen_bits[i] | (prop_old & gen_bits[i - prop_dist])
            if i >= prop_dist * 2:  # to prevent creating unnecessary nets and wires
                prop_bits[i] = prop_old & prop_bits[i - prop_dist]
        prop_dist *= 2

    # assembling the result of the addition
    # preparing the cin (and conveniently shifting the gen bits)
    gen_bits.insert(0, pyrtl.as_wires(cin))
    return pyrtl.concat_list(gen_bits) ^ prop_orig


Instruction:
Write a Python 3 function that can
add two wirevectors up in an efficient manner.

Response:
def carrysave_adder(a, b, c, final_adder=ripple_add):
    """
    Adds three wirevectors up in an efficient manner
    :param WireVector a, b, c : the three wires to add up
    :param function final_adder : The adder to use to do the final addition
    :return: a wirevector with length 2 longer than the largest input
    """
    a, b, c = libutils.match_bitwidth(a, b, c)
    partial_sum = a ^ b ^ c
    shift_carry = (a | b) & (a | c) & (b | c)
    return pyrtl.concat(final_adder(partial_sum[1:], shift_carry), partial_sum[0])


Instruction:
Explain what the following Python 3 code does
def cla_adder(a, b, cin=0, la_unit_len=4):
    a, b = pyrtl.match_bitwidth(a, b)
    if len(a) <= la_unit_len:
        sum, cout = _cla_adder_unit(a, b, cin)
        return pyrtl.concat(cout, sum)
    else:
        sum, cout = _cla_adder_unit(a[0:la_unit_len], b[0:la_unit_len], cin)
        msbits = cla_adder(a[la_unit_len:], b[la_unit_len:], cout, la_unit_len)
        return pyrtl.concat(msbits, sum)

Response: A simple algorithm for calculating the carry bits of a single ripple adder.


Instruction:
Explain what the following Python 3 code does
def _cla_adder_unit(a, b, cin):
    gen = a & b
    prop = a ^ b
    assert(len(prop) == len(gen))

    carry = [gen[0] | prop[0] & cin]
    sum_bit = prop[0] ^ cin

    cur_gen = gen[0]
    cur_prop = prop[0]
    for i in range(1, len(prop)):
        cur_gen = gen[i] | (prop[i] & cur_gen)
        cur_prop = cur_prop & prop[i]
        sum_bit = pyrtl.concat(prop[i] ^ carry[i - 1], sum_bit)
        carry.append(gen[i] | (prop[i] & carry[i-1]))
    cout = cur_gen | (cur_prop & cin)
    return sum_bit, cout

Response: This function calculates the cout signal and the gen and propogation signals for the next unit.


Instruction:
Can you create a Python 3 function that
builds a write port.

Response:
def _build(self, addr, data, enable):
        """ Builds a write port. """
        if self.max_write_ports is not None:
            self.write_ports += 1
            if self.write_ports > self.max_write_ports:
                raise PyrtlError('maximum number of write ports (%d) exceeded' %
                                 self.max_write_ports)
        writeport_net = LogicNet(
            op='@',
            op_param=(self.id, self),
            args=(addr, data, enable),
            dests=tuple())
        working_block().add_net(writeport_net)
        self.writeport_nets.append(writeport_net)


Instruction:
How would you implement a function in Python 3 that
builds a single cycle AES Encryption circuit containing the plaintext and the AES key.

Response:
def encryption(self, plaintext, key):
        """
        Builds a single cycle AES Encryption circuit

        :param WireVector plaintext: text to encrypt
        :param WireVector key: AES key to use to encrypt
        :return: a WireVector containing the ciphertext

        """
        if len(plaintext) != self._key_len:
            raise pyrtl.PyrtlError("Ciphertext length is invalid")
        if len(key) != self._key_len:
            raise pyrtl.PyrtlError("key length is invalid")

        key_list = self._key_gen(key)
        t = self._add_round_key(plaintext, key_list[0])

        for round in range(1, 11):
            t = self._sub_bytes(t)
            t = self._shift_rows(t)
            if round != 10:
                t = self._mix_columns(t)
            t = self._add_round_key(t, key_list[round])
        return t


Instruction:
How would you code a function in Python 3 to
build a multiple cycle AES Encryption state machine.

Response:
def encrypt_state_m(self, plaintext_in, key_in, reset):
        """
        Builds a multiple cycle AES Encryption state machine circuit

        :param reset: a one bit signal telling the state machine
          to reset and accept the current plaintext and key
        :return ready, cipher_text: ready is a one bit signal showing
          that the encryption result (cipher_text) has been calculated.

        """
        if len(key_in) != len(plaintext_in):
            raise pyrtl.PyrtlError("AES key and plaintext should be the same length")

        plain_text, key = (pyrtl.Register(len(plaintext_in)) for i in range(2))
        key_exp_in, add_round_in = (pyrtl.WireVector(len(plaintext_in)) for i in range(2))

        counter = pyrtl.Register(4, 'counter')
        round = pyrtl.WireVector(4, 'round')
        counter.next <<= round
        sub_out = self._sub_bytes(plain_text)
        shift_out = self._shift_rows(sub_out)
        mix_out = self._mix_columns(shift_out)
        key_out = self._key_expansion(key, counter)
        add_round_out = self._add_round_key(add_round_in, key_exp_in)
        with pyrtl.conditional_assignment:
            with reset == 1:
                round |= 0
                key_exp_in |= key_in  # to lower the number of cycles
                plain_text.next |= add_round_out
                key.next |= key_in
                add_round_in |= plaintext_in

            with counter == 10:  # keep everything the same
                round |= counter
                plain_text.next |= plain_text

            with pyrtl.otherwise:  # running through AES
                round |= counter + 1
                key_exp_in |= key_out
                plain_text.next |= add_round_out
                key.next |= key_out
                with counter == 9:
                    add_round_in |= shift_out
                with pyrtl.otherwise:
                    add_round_in |= mix_out

        ready = (counter == 10)
        return ready, plain_text


Instruction:
Can you implement a function in Python 3 that
builds a single cycle AES Decryption circuit containing the plaintext data.

Response:
def decryption(self, ciphertext, key):
        """
        Builds a single cycle AES Decryption circuit

        :param WireVector ciphertext: data to decrypt
        :param WireVector key: AES key to use to encrypt (AES is symmetric)
        :return: a WireVector containing the plaintext
        """
        if len(ciphertext) != self._key_len:
            raise pyrtl.PyrtlError("Ciphertext length is invalid")
        if len(key) != self._key_len:
            raise pyrtl.PyrtlError("key length is invalid")
        key_list = self._key_gen(key)
        t = self._add_round_key(ciphertext, key_list[10])

        for round in range(1, 11):
            t = self._inv_shift_rows(t)
            t = self._sub_bytes(t, True)
            t = self._add_round_key(t, key_list[10 - round])
            if round != 10:
                t = self._mix_columns(t, True)

        return t


Instruction:
Make a summary of the following Python 3 code
def decryption_statem(self, ciphertext_in, key_in, reset):
        if len(key_in) != len(ciphertext_in):
            raise pyrtl.PyrtlError("AES key and ciphertext should be the same length")

        cipher_text, key = (pyrtl.Register(len(ciphertext_in)) for i in range(2))
        key_exp_in, add_round_in = (pyrtl.WireVector(len(ciphertext_in)) for i in range(2))

        # this is not part of the state machine as we need the keys in
        # reverse order...
        reversed_key_list = reversed(self._key_gen(key_exp_in))

        counter = pyrtl.Register(4, 'counter')
        round = pyrtl.WireVector(4)
        counter.next <<= round

        inv_shift = self._inv_shift_rows(cipher_text)
        inv_sub = self._sub_bytes(inv_shift, True)
        key_out = pyrtl.mux(round, *reversed_key_list, default=0)
        add_round_out = self._add_round_key(add_round_in, key_out)
        inv_mix_out = self._mix_columns(add_round_out, True)

        with pyrtl.conditional_assignment:
            with reset == 1:
                round |= 0
                key.next |= key_in
                key_exp_in |= key_in  # to lower the number of cycles needed
                cipher_text.next |= add_round_out
                add_round_in |= ciphertext_in

            with counter == 10:  # keep everything the same
                round |= counter
                cipher_text.next |= cipher_text

            with pyrtl.otherwise:  # running through AES
                round |= counter + 1

                key.next |= key
                key_exp_in |= key
                add_round_in |= inv_sub
                with counter == 9:
                    cipher_text.next |= add_round_out
                with pyrtl.otherwise:
                    cipher_text.next |= inv_mix_out

        ready = (counter == 10)
        return ready, cipher_text

Response: Builds a multiple cycle AES Decryption state machine.


Instruction:
Can you tell what is the following Python 3 function doing
def _g(self, word, key_expand_round):
        import numbers
        self._build_memories_if_not_exists()
        a = libutils.partition_wire(word, 8)
        sub = [self.sbox[a[index]] for index in (3, 0, 1, 2)]
        if isinstance(key_expand_round, numbers.Number):
            rcon_data = self._rcon_data[key_expand_round + 1]  # int value
        else:
            rcon_data = self.rcon[key_expand_round + 1]
        sub[3] = sub[3] ^ rcon_data
        return pyrtl.concat_list(sub)

Response: One - byte left circular rotation substitution of each byte


Instruction:
Write a Python 3 script for
shallowing dictionary merge Args: a: dict to extend b: dict to apply to a Returns: new instance of the same type as _a_, with _a_ and _b_ merged.

Response:
def extend(*args):
    """shallow dictionary merge

    Args:
        a: dict to extend
        b: dict to apply to a

    Returns:
        new instance of the same type as _a_, with _a_ and _b_ merged.
    """
    if not args:
        return {}

    first = args[0]
    rest = args[1:]
    out = type(first)(first)
    for each in rest:
        out.update(each)
    return out


Instruction:
Can you generate the documentation for the following Python 3 function
def input_from_blif(blif, block=None, merge_io_vectors=True):
    import pyparsing
    import six
    from pyparsing import (Word, Literal, OneOrMore, ZeroOrMore,
                           Suppress, Group, Keyword)

    block = working_block(block)

    try:
        blif_string = blif.read()
    except AttributeError:
        if isinstance(blif, six.string_types):
            blif_string = blif
        else:
            raise PyrtlError('input_blif expecting either open file or string')

    def SKeyword(x):
        return Suppress(Keyword(x))

    def SLiteral(x):
        return Suppress(Literal(x))

    def twire(x):
        """ find or make wire named x and return it """
        s = block.get_wirevector_by_name(x)
        if s is None:
            s = WireVector(bitwidth=1, name=x)
        return s

    # Begin BLIF language definition
    signal_start = pyparsing.alphas + '$:[]_<>\\\/'
    signal_middle = pyparsing.alphas + pyparsing.nums + '$:[]_<>\\\/.'
    signal_id = Word(signal_start, signal_middle)
    header = SKeyword('.model') + signal_id('model_name')
    input_list = Group(SKeyword('.inputs') + OneOrMore(signal_id))('input_list')
    output_list = Group(SKeyword('.outputs') + OneOrMore(signal_id))('output_list')

    cover_atom = Word('01-')
    cover_list = Group(ZeroOrMore(cover_atom))('cover_list')
    namesignal_list = Group(OneOrMore(signal_id))('namesignal_list')
    name_def = Group(SKeyword('.names') + namesignal_list + cover_list)('name_def')

    # asynchronous Flip-flop
    dffas_formal = (SLiteral('C=') + signal_id('C') +
                    SLiteral('R=') + signal_id('R') +
                    SLiteral('D=') + signal_id('D') +
                    SLiteral('Q=') + signal_id('Q'))
    dffas_keyword = SKeyword('$_DFF_PN0_') | SKeyword('$_DFF_PP0_')
    dffas_def = Group(SKeyword('.subckt') + dffas_keyword + dffas_formal)('dffas_def')

    # synchronous Flip-flop
    dffs_def = Group(SKeyword('.latch') +
                     signal_id('D') +
                     signal_id('Q') +
                     SLiteral('re') +
                     signal_id('C'))('dffs_def')
    command_def = name_def | dffas_def | dffs_def
    command_list = Group(OneOrMore(command_def))('command_list')

    footer = SKeyword('.end')
    model_def = Group(header + input_list + output_list + command_list + footer)
    model_list = OneOrMore(model_def)
    parser = model_list.ignore(pyparsing.pythonStyleComment)

    # Begin actually reading and parsing the BLIF file
    result = parser.parseString(blif_string, parseAll=True)
    # Blif file with multiple models (currently only handles one flattened models)
    assert(len(result) == 1)
    clk_set = set([])
    ff_clk_set = set([])

    def extract_inputs(model):
        start_names = [re.sub(r'\[([0-9]+)\]$', '', x) for x in model['input_list']]
        name_counts = collections.Counter(start_names)
        for input_name in name_counts:
            bitwidth = name_counts[input_name]
            if input_name == 'clk':
                clk_set.add(input_name)
            elif not merge_io_vectors or bitwidth == 1:
                block.add_wirevector(Input(bitwidth=1, name=input_name))
            else:
                wire_in = Input(bitwidth=bitwidth, name=input_name, block=block)
                for i in range(bitwidth):
                    bit_name = input_name + '[' + str(i) + ']'
                    bit_wire = WireVector(bitwidth=1, name=bit_name, block=block)
                    bit_wire <<= wire_in[i]

    def extract_outputs(model):
        start_names = [re.sub(r'\[([0-9]+)\]$', '', x) for x in model['output_list']]
        name_counts = collections.Counter(start_names)
        for output_name in name_counts:
            bitwidth = name_counts[output_name]
            if not merge_io_vectors or bitwidth == 1:
                block.add_wirevector(Output(bitwidth=1, name=output_name))
            else:
                wire_out = Output(bitwidth=bitwidth, name=output_name, block=block)
                bit_list = []
                for i in range(bitwidth):
                    bit_name = output_name + '[' + str(i) + ']'
                    bit_wire = WireVector(bitwidth=1, name=bit_name, block=block)
                    bit_list.append(bit_wire)
                wire_out <<= concat(*bit_list)

    def extract_commands(model):
        # for each "command" (dff or net) in the model
        for command in model['command_list']:
            # if it is a net (specified as a cover)
            if command.getName() == 'name_def':
                extract_cover(command)
            # else if the command is a d flop flop
            elif command.getName() == 'dffas_def' or command.getName() == 'dffs_def':
                extract_flop(command)
            else:
                raise PyrtlError('unknown command type')

    def extract_cover(command):
        netio = command['namesignal_list']
        if len(command['cover_list']) == 0:
            output_wire = twire(netio[0])
            output_wire <<= Const(0, bitwidth=1, block=block)  # const "FALSE"
        elif command['cover_list'].asList() == ['1']:
            output_wire = twire(netio[0])
            output_wire <<= Const(1, bitwidth=1, block=block)  # const "TRUE"
        elif command['cover_list'].asList() == ['1', '1']:
            # Populate clock list if one input is already a clock
            if(netio[1] in clk_set):
                clk_set.add(netio[0])
            elif(netio[0] in clk_set):
                clk_set.add(netio[1])
            else:
                output_wire = twire(netio[1])
                output_wire <<= twire(netio[0])  # simple wire
        elif command['cover_list'].asList() == ['0', '1']:
            output_wire = twire(netio[1])
            output_wire <<= ~ twire(netio[0])  # not gate
        elif command['cover_list'].asList() == ['11', '1']:
            output_wire = twire(netio[2])
            output_wire <<= twire(netio[0]) & twire(netio[1])  # and gate
        elif command['cover_list'].asList() == ['00', '1']:
            output_wire = twire(netio[2])
            output_wire <<= ~ (twire(netio[0]) | twire(netio[1]))  # nor gate
        elif command['cover_list'].asList() == ['1-', '1', '-1', '1']:
            output_wire = twire(netio[2])
            output_wire <<= twire(netio[0]) | twire(netio[1])  # or gate
        elif command['cover_list'].asList() == ['10', '1', '01', '1']:
            output_wire = twire(netio[2])
            output_wire <<= twire(netio[0]) ^ twire(netio[1])  # xor gate
        elif command['cover_list'].asList() == ['1-0', '1', '-11', '1']:
            output_wire = twire(netio[3])
            output_wire <<= (twire(netio[0]) & ~ twire(netio[2])) \
                | (twire(netio[1]) & twire(netio[2]))   # mux
        elif command['cover_list'].asList() == ['-00', '1', '0-0', '1']:
            output_wire = twire(netio[3])
            output_wire <<= (~twire(netio[1]) & ~twire(netio[2])) \
                | (~twire(netio[0]) & ~twire(netio[2]))
        else:
            raise PyrtlError('Blif file with unknown logic cover set "%s"'
                             '(currently gates are hard coded)' % command['cover_list'])

    def extract_flop(command):
        if(command['C'] not in ff_clk_set):
            ff_clk_set.add(command['C'])

        # Create register and assign next state to D and output to Q
        regname = command['Q'] + '_reg'
        flop = Register(bitwidth=1, name=regname)
        flop.next <<= twire(command['D'])
        flop_output = twire(command['Q'])
        flop_output <<= flop

    for model in result:
        extract_inputs(model)
        extract_outputs(model)
        extract_commands(model)

Response: Read a string of blif file or string as input updating the block appropriately