simpctr.html 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <html>
  2. <head>
  3. <title>Simple Gray Code Counter</title>
  4. </head>
  5. <body bgcolor="FFFFFF">
  6. <h1>Simple Gray Code Counter</h1>
  7. <p>Often we want components that aren't exclusively combinational
  8. in nature - that is, we want the component to have some memory.
  9. There is an important subtlety in defining such components: You
  10. can't have the component itself store the state, because an
  11. individual component can appear many times in the same circuit.
  12. It can't appear directly within a circuit multiple times, but
  13. it can appear multiple times if it appears in a subcircuit that
  14. is used several times.</p>
  15. <p>The solution is to create a new class for representing the
  16. object's current state, and to associate instances of this with
  17. the component through the parent circuit's state. In this example,
  18. which implements an edge-triggered 4-bit Gray code counter, we define a
  19. <code>CounterData</code> class to represent the counter's state, in addition
  20. to the <code>InstanceFactory</code> subclass as illustrated previously.
  21. The <code>CounterData</code> object remembers both the counter's
  22. current value, as well as the last clock input seen (to detect
  23. rising edges).</p>
  24. <h2>CounterData</h2>
  25. <pre>
  26. package com.cburch.gray;
  27. import com.cburch.logisim.data.BitWidth;
  28. import com.cburch.logisim.data.Value;
  29. import com.cburch.logisim.instance.InstanceData;
  30. import com.cburch.logisim.instance.InstanceState;
  31. /** Represents the state of a counter. */
  32. class CounterData implements InstanceData, Cloneable {
  33. /** Retrieves the state associated with this counter in the circuit state,
  34. * generating the state if necessary.
  35. */
  36. public static CounterData get(InstanceState state, BitWidth width) {
  37. CounterData ret = (CounterData) state.getData();
  38. if(ret == null) {
  39. // If it doesn't yet exist, then we'll set it up with our default
  40. // values and put it into the circuit state so it can be retrieved
  41. // in future propagations.
  42. ret = new CounterData(null, Value.createKnown(width, 0));
  43. state.setData(ret);
  44. } else if(!ret.value.getBitWidth().equals(width)) {
  45. ret.value = ret.value.extendWidth(width.getWidth(), Value.FALSE);
  46. }
  47. return ret;
  48. }
  49. /** The last clock input value observed. */
  50. private Value lastClock;
  51. /** The current value emitted by the counter. */
  52. private Value value;
  53. /** Constructs a state with the given values. */
  54. public CounterData(Value lastClock, Value value) {
  55. this.lastClock = lastClock;
  56. this.value = value;
  57. }
  58. /** Returns a copy of this object. */
  59. public Object clone() {
  60. // We can just use what super.clone() returns: The only instance variables are
  61. // Value objects, which are immutable, so we don't care that both the copy
  62. // and the copied refer to the same Value objects. If we had mutable instance
  63. // variables, then of course we would need to clone them.
  64. try { return super.clone(); }
  65. catch(CloneNotSupportedException e) { return null; }
  66. }
  67. /** Updates the last clock observed, returning true if triggered. */
  68. public boolean updateClock(Value value) {
  69. Value old = lastClock;
  70. lastClock = value;
  71. return old == Value.FALSE && value == Value.TRUE;
  72. }
  73. /** Returns the current value emitted by the counter. */
  74. public Value getValue() {
  75. return value;
  76. }
  77. /** Updates the current value emitted by the counter. */
  78. public void setValue(Value value) {
  79. this.value = value;
  80. }
  81. }
  82. </pre>
  83. <h2>SimpleCounter</h2>
  84. <pre>
  85. package com.cburch.gray;
  86. import com.cburch.logisim.data.BitWidth;
  87. import com.cburch.logisim.data.Bounds;
  88. import com.cburch.logisim.data.Direction;
  89. import com.cburch.logisim.instance.InstanceFactory;
  90. import com.cburch.logisim.instance.InstancePainter;
  91. import com.cburch.logisim.instance.InstanceState;
  92. import com.cburch.logisim.instance.Port;
  93. import com.cburch.logisim.util.GraphicsUtil;
  94. import com.cburch.logisim.util.StringUtil;
  95. /** Manufactures a simple counter that iterates over the 4-bit Gray Code. This
  96. * example illustrates how a component can maintain its own internal state. All
  97. * of the code relevant to state, though, appears in CounterData class. */
  98. class SimpleGrayCounter extends InstanceFactory {
  99. private static final BitWidth BIT_WIDTH = BitWidth.create(4);
  100. // Again, notice how we don't have any instance variables related to an
  101. // individual instance's state. We can't put that here, because only one
  102. // SimpleGrayCounter object is ever created, and its job is to manage all
  103. // instances that appear in any circuits.
  104. public SimpleGrayCounter() {
  105. super("Gray Counter (Simple)");
  106. setOffsetBounds(Bounds.create(-30, -15, 30, 30));
  107. setPorts(new Port[] {
  108. new Port(-30, 0, Port.INPUT, 1),
  109. new Port( 0, 0, Port.OUTPUT, BIT_WIDTH.getWidth()),
  110. });
  111. }
  112. public void propagate(InstanceState state) {
  113. // Here I retrieve the state associated with this component via a helper
  114. // method. In this case, the state is in a CounterData object, which is
  115. // also where the helper method is defined. This helper method will end
  116. // up creating a CounterData object if one doesn't already exist.
  117. CounterData cur = CounterData.get(state, BIT_WIDTH);
  118. boolean trigger = cur.updateClock(state.getPort(0));
  119. if(trigger) cur.setValue(GrayIncrementer.nextGray(cur.getValue()));
  120. state.setPort(1, cur.getValue(), 9);
  121. // (You might be tempted to determine the counter's current value
  122. // via state.getPort(1). This is erroneous, though, because another
  123. // component may be pushing a value onto the same point, which would
  124. // "corrupt" the value found there. We really do need to store the
  125. // current value in the instance.)
  126. }
  127. public void paintInstance(InstancePainter painter) {
  128. painter.drawBounds();
  129. painter.drawClock(0, Direction.EAST); // draw a triangle on port 0
  130. painter.drawPort(1); // draw port 1 as just a dot
  131. // Display the current counter value centered within the rectangle.
  132. // However, if the context says not to show state (as when generating
  133. // printer output), then skip this.
  134. if(painter.getShowState()) {
  135. CounterData state = CounterData.get(painter, BIT_WIDTH);
  136. Bounds bds = painter.getBounds();
  137. GraphicsUtil.drawCenteredText(painter.getGraphics(),
  138. StringUtil.toHexString(BIT_WIDTH.getWidth(), state.getValue().toIntValue()),
  139. bds.getX() + bds.getWidth() / 2,
  140. bds.getY() + bds.getHeight() / 2);
  141. }
  142. }
  143. }
  144. </pre>
  145. <p><strong>Next:</strong> <a href="counter.html">Gray Code Counter</a>.</p>
  146. </body>
  147. </html>