<!-- Gray Code Incrementer --> 格雷码增量器

# 格雷码增量器

库中包含的每个组件都是通过创建 `com.cburch.logisim.instance` 包中的 `InstanceFactory` 子类来定义的。 该子类包含所有涉及的代码

（这里我们描述当前版本 Logisim-evolution 的 API。您可能会发现一些为旧版本 Logisim-evolution 开发的库，其中通过定义两个类来开发组件，一个扩展 `Component` ，另一个扩展 `ComponentFactory` 。版本 2.3.0 引入了更简单的 `InstanceFactory` API；旧的技术已被弃用。）

三个 Logisim-evolution 包定义了与定义组件库相关的大多数类。

`com.cburch.logisim.instance`

  包含与定义组件具体相关的类，包括 InstanceFactory、InstanceState、InstancePainter 和 Instance 类。

`com.cburch.logisim.data`

  包含与组件关联的数据元素相关的类，例如用于表示边界矩形的 `Bounds` 类或用于表示导线上可能存在的值的 `Value` 类。

`com.cburch.logisim.tools`

  包含与库定义相关的类。

## About Gray codes

在继续之前，让我简要描述一下这些示例所基于的格雷码。 了解这些示例的工作原理并不重要，因此如果您愿意，您可以安全地跳到下面的代码 - 特别是如果您已经了解格雷码。

格雷码是一种迭代 n 位序列的技术（以 Frank Gray 命名），每一步仅更改一位。 作为示例，请考虑下面列出的 4 位格雷码。

> 000 0 00 0 1 001 1 0 0 10 |  | 011 0 01 1 1 010 1 0 100 |  | 110 0 11 0 1 111 1 1 1 10 |  | 101 0 10 1 1 100 1 1 000

每个值都有一个带下划线的位，该位将针对序列中的下一个值而更改。 例如，0000之后是0001，其中最后一位已被切换，因此最后一位带有下划线。

Logisim 的内置组件不包含任何使用格雷码的内容。 但电子设计师发现格雷码有时很有用。 格雷码的一个特别值得注意的例子是沿着卡诺图中的轴。

## GrayIncrementer

这是一个最小的示例，说明了定义组件的基本元素。 这个特定的组件是一个增量器，它接受多位输入并按顺序生成下一个格雷码。

    package com.cburch.gray;

    import com.cburch.logisim.data.Attribute;
    import com.cburch.logisim.data.BitWidth;
    import com.cburch.logisim.data.Bounds;
    import com.cburch.logisim.data.Value;
    import com.cburch.logisim.instance.InstanceFactory;
    import com.cburch.logisim.instance.InstancePainter;
    import com.cburch.logisim.instance.InstanceState;
    import com.cburch.logisim.instance.Port;
    import com.cburch.logisim.instance.StdAttr;

    /** This component takes a multibit input and outputs the value that follows it
     * in Gray Code. For instance, given input 0100 the output is 1100. */
    class GrayIncrementer extends InstanceFactory {
        /* Note that there are no instance variables. There is only one instance of
         * this class created, which manages all instances of the component. Any
         * information associated with individual instances should be handled
         * through attributes. For GrayIncrementer, each instance has a "bit width"
         * that it works with, and so we'll have an attribute. */

        /** The constructor configures the factory. */
        GrayIncrementer() {
            super("Gray Code Incrementer");

            /* This is how we can set up the attributes for GrayIncrementers. In
             * this case, there is just one attribute - the width - whose default
             * is 4. The StdAttr class defines several commonly occurring
             * attributes, including one for "bit width." It's best to use those
             * StdAttr attributes when appropriate: A user can then select several
             * components (even from differing factories) with the same attribute
             * and modify them all at once. */
            setAttributes(new Attribute[] { StdAttr.WIDTH },
                    new Object[] { BitWidth.create(4) });

            /* The "offset bounds" is the location of the bounding rectangle
             * relative to the mouse location. Here, we're choosing the component to
             * be 30x30, and we're anchoring it relative to its primary output
             * (as is typical for Logisim), which happens to be in the center of the
             * east edge. Thus, the top left corner of the bounding box is 30 pixels
             * west and 15 pixels north of the mouse location. */
            setOffsetBounds(Bounds.create(-30, -15, 30, 30));

            /* The ports are locations where wires can be connected to this
             * component. Each port object says where to find the port relative to
             * the component's anchor location, then whether the port is an
             * input/output/both, and finally the expected bit width for the port.
             * The bit width can be a constant (like 1) or an attribute (as here).
             */
            setPorts(new Port[] {
                    new Port(-30, 0, Port.INPUT, StdAttr.WIDTH),
                    new Port(0, 0, Port.OUTPUT, StdAttr.WIDTH),
                });
        }

        /** Computes the current output for this component. This method is invoked
         * any time any of the inputs change their values; it may also be invoked in
         * other circumstances, even if there is no reason to expect it to change
         * anything. */
        public void propagate(InstanceState state) {
            // First we retrieve the value being fed into the input. Note that in
            // the setPorts invocation above, the component's input was included at
            // index 0 in the parameter array, so we use 0 as the parameter below.
            Value in = state.getPort(0);

            // Now compute the output. We've farmed this out to a helper method,
            // since the same logic is needed for the library's other components.
            Value out = nextGray(in);

            // Finally we propagate the output into the circuit. The first parameter
            // is 1 because in our list of ports (configured by invocation of
            // setPorts above) the output is at index 1. The second parameter is the
            // value we want to send on that port. And the last parameter is its
            // "delay" - the number of steps it will take for the output to update
            // after its input.
            state.setPort(1, out, out.getWidth() + 1);
        }

        /** Says how an individual instance should appear on the canvas. */
        public void paintInstance(InstancePainter painter) {
            // As it happens, InstancePainter contains several convenience methods
            // for drawing, and we'll use those here. Frequently, you'd want to
            // retrieve its Graphics object (painter.getGraphics) so you can draw
            // directly onto the canvas.
            painter.drawRectangle(painter.getBounds(), "G+1");
            painter.drawPorts();
        }

        /** Computes the next gray value in the sequence after prev. This static
         * method just does some bit twiddling; it doesn't have much to do with
         * Logisim except that it manipulates Value and BitWidth objects. */
        static Value nextGray(Value prev) {
            BitWidth bits = prev.getBitWidth();
            if(!prev.isFullyDefined()) return Value.createError(bits);
            int x = prev.toIntValue();
            int ct = (x >> 16) ^ x; // compute parity of x
            ct = (ct >> 8) ^ ct;
            ct = (ct >> 4) ^ ct;
            ct = (ct >> 2) ^ ct;
            ct = (ct >> 1) ^ ct;
            if((ct & 1) == 0) { // if parity is even, flip 1's bit
                x = x ^ 1;
            } else { // else flip bit just above last 1
                int y = x ^ (x & (x - 1)); // first compute the last 1
                y = (y << 1) & bits.getMask();
                x = (y == 0 ? 0 : x ^ y);
            }
            return Value.createKnown(bits, x);
        }
    }

This example by itself is not enough to create a working JAR file; you must also provide a Library class, as illustrated on the next page.

Next: Library Class .