| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- <html>
- <head>
- <title>Gray Code Incrementer</title>
- </head>
- <body bgcolor="FFFFFF">
- <h1>Gray Code Incrementer</h1>
- <p>Each component included in a library is defined by creating a subclass of
- <code>InstanceFactory</code> found in the
- <code>com.cburch.logisim.instance</code> package. This subclass has all
- the code involved</p>
- <p>(Here we're describing the API for the current version of Logisim.
- You may find some libraries developed for older versions of Logisim, in
- which components were developed by defining two classes, one extending
- <code>Component</code> and another extending <code>ComponentFactory</code>.
- Version 2.3.0 introduced the much simpler <code>InstanceFactory</code> API; the
- older technique is deprecated.)</p>
- <p>Three Logisim packages define most of the classes relevant to defining
- component libraries.</p>
- <dl>
- <dt><code>com.cburch.logisim.instance</code></dt>
- <dd><p>Contains classes specifically related to defining components,
- including the <code>InstanceFactory</code>, <code>InstanceState</code>,
- <code>InstancePainter</code>, and <code>Instance</code> classes.</p></dd>
- <dt><code>com.cburch.logisim.data</code></dt>
- <dd><p>Contains classes related to data elements associated with components,
- such as the <code>Bounds</code> class for representing bounding rectangles
- or the <code>Value</code> class for representing values that can
- exist on a wire.</p></dd>
- <dt><code>com.cburch.logisim.tools</code></dt>
- <dd><p>Contains classes related to the library definition.</p></dd>
- </dl>
- <h2>About Gray codes</h2>
- <p>Before we go on, let me briefly describe the Gray code on which these
- examples are based. It's not really important to understanding how these
- examples work, so you can safely skip to the code below if you wish -
- particularly if you already know Gray codes.</p>
- <p>Gray code is a technique (named after Frank Gray) for iterating through
- <var>n</var>-bit sequences with only one bit changed for each step. As an
- example, consider the 4-bit Gray code listed below.</p>
- <blockquote><table><tbody>
- <tr><td valign="top">000<u>0</u>
- <br>00<u>0</u>1
- <br>001<u>1</u>
- <br>0<u>0</u>10
- </td><td>
- </td><td valign="top">011<u>0</u>
- <br>01<u>1</u>1
- <br>010<u>1</u>
- <br><u>0</u>100
- </td><td>
- </td><td valign="top">110<u>0</u>
- <br>11<u>0</u>1
- <br>111<u>1</u>
- <br>1<u>1</u>10
- </td><td>
- </td><td valign="top">101<u>0</u>
- <br>10<u>1</u>1
- <br>100<u>1</u>
- <br><u>1</u>000
- </td></tr></tbody></table></blockquote>
- <p>Each value has the bit underlined that will change for the next value in
- the sequence. For example, after 0000 comes 0001, in which the final bit has
- been toggled, so the final bit is underlined.</p>
- <p>Logisim's built-in components don't include anything working with Gray codes.
- But electronics designers find Gray codes useful sometimes. One
- particularly notable instance of Gray codes is along the axes in Karnaugh
- maps.</p>
- <h2>GrayIncrementer</h2>
- <p>This is a minimal example illustrating the essential elements
- to defining a component. This particular component is an incrementer,
- which takes an multibit input and produces the next Gray code following it
- in sequence.</p>
- <pre>
- 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);
- }
- }
- </pre>
- <p>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.</p>
- <p><strong>Next:</strong> <a href="library.html">Library Class</a>.</p>
- </body>
- </html>
|