Survivalcraft provides a convenient single-block binary up/down counter. However, there are many instances where a counter with more features are needed. This article will explain other ways to make counters and why and where they may be used, as well as the advantages and disadvantages of these alternate designs.
Random Sequence(s) Counter
This counter is simple in design and has the greatest flexibility. However, it must be carefully programmed. As shown, there are two sequence inputs but this can easily be increased to four. Each button steps the counter through a specific sequence of outputs. Each sequence can be unique and they don't have to be sequential numbers, either. I.e., one sequence could be 1-7-4-A-C-6-2-9-7-1. The total number of different outputs must be 16 or less and you cannot repeat any number in the sequence. You also have to be careful that one sequence doesn't include a number that may put another sequence in a state it can't recover from. This would only happen in 'strange' sequences. Any number that one sequence can generate must be covered by every sequence that might follow it.
One advantage to that circuit is it easily makes short sequence, up/down counters. The circuit shown can be used this way. Note that there are two connections to each button. This takes advantage of the 'isolated' outputs they have. If you just want one connection, use an 'OR' gate between the buttons.
The circuit shown has 2 buttons (sequences) and they are meant to be UP and DOWN. Since they are connected to the 1 and 3 bit inputs on the A>D, we will only program the corresponding rows of the Memory Bank. Let's assume we want a counter to run 0-1-2-3-4 up and 4-3-2-1-0 down.
The UP line translates to a "1" input to the bank and the DOWN line to a "4", so only these rows (high addresses) are used. The low addresses represent the current counter output so in each row, we just place the next output in each sequence. For the UP function (row '1'), under the 0 we will place a 1. Under the 1, a 2. Under the 3, a 4 and under the 4, a 0. This way the count will start over and keep cycling.
The DOWN function (row '4') is programmed similarly but with decreasing numbers.. Under the 0, we place a 4, under the 1, a 0 and so on. That's all the programming the bank needs.
The adjustable delay gate is fed to the clock input of the bank and this will "latch" the output when it goes high. Otherwise the output would change when the input does and it would just keep changing constantly. By using the clock input, the output will only change when the clock first goes active. The delay gate must be set to a delay of 3 ticks, or 0.03 seconds because the clock must wait for the other inputs to be stable. If you put the 'OR' gate in, it only needs to be 2.
Presettable, Bus-based Counter
Many times a counter needs to be started from a specific value. The binary counter in the game cannot be preset to a value. The circuit here not only allows an initial value to be set, it also includes buffers that allow it to be connected to a data bus. The bus is expected to carry the preset value when loading is done and will carry the counter output when the circuit's output buffer is enabled.
This is the schematic for the circuit. As you can see it's fairly simple. There are three buffers (AND gates) and two Memory Banks.
The bank labeled "count" holds the counter output value. The current value is always available at the "Count Out" signal. When this value is needed to be carried on the bus, the O.E. control must be set to '1'. This bank is programmed in the first line only, with: 0123456789abcdef
The bank labeled "+1" provides for incrementing the "count" bank. For every output value of the count bank, the +1 bank is programmed to output that value +1. If the 'Inc Sel' signal is active then the output from the +1 bank is at the input of the count bank. When the 'Pulse' signal goes high, this value is locked into the count bank. The output of the count bank then increases by 1 and a normal count is achieved. Note that since the clock input to the banks are "edge-triggered" the change will NOT feed back into the bank and cause unstable changes. The +1 bank is programmed with: 123456789abcdef0 Note that each value is +1 from its location. That's how the +1 is performed.
The counter can be set to any value present on the data bus in addition to normal counting. The 'Load Sel' signal must be held high while the 'Pulse' control goes high. The Count bank will then hold that value and any further counting will be done from that value.
There can be many variations on this circuit. The O.E. buffer may not be needed at all, if this circuit is not run off a data bus, or the output doesn't need to be presented to the bus. The other buffers could be implemented with additional memory banks so the control signals could be a combined 'analog' signal. This may make the layout simpler in some cases. Then a single analog control signal runs to both buffer banks. The banks would be programmed as demultiplexers.
If you don't need to preload a random value but a specific starting value, both select buffers may be removed. Only a single control signal is needed to tell the circuit whether to count or to load and this signal may be sent to the H input on the +1 bank. This bank would then hold the fixed preset value in another location, in addition to the +1 row given above. Which row the preset value goes in would depend on how the set/count signal is created.
If we assume a digital control signal and a '0' on this signal tells it to count normally, then a '1' on this signal would prepare the circuit to load the preset value. In this case, the row-0 value is the same as given above, and the preset value will be programmed into every space in the 'F' row.
As an example, let's assume that we want a preset of '2'. Then the bank's complete program would be:
This idea may even be expanded further to include up to 15 different possible load values. Which value is loaded would depend on the value of the control input.
A -1 count bank could be included, or a -2, or a +3, etc. Each one could be a separate bank, controlled by a single digital signal.
Or they may be incorporated into a single bank that uses an encoded control signal. The possibilities are nearly unlimited. We would then have a fully programmable, variable sequence state-machine. The next state is set within the bank and can output any hex value for any current state at the one input and the 'program sequence' present at the other bank input.The memory bank programming is all that is needed to change this behavior.
Loadable Up/Down Counter
The last example is of a complete, loadable up/down counter unit. This circuit can be daisy-chained to any length desired (within reason and the limits of Survivalcraft electrics) and is very flexible. However, it is also the most complicated. It is intended to be connected to a data bus and will also supply an unbuffered, steady output. This output can be used to address a section of memory and will function as a Stack Pointer or Program Counter. The local (steady) outputs are in hex (analog) form as well as the data bus I/O and change only in response to the rising edge of the clock.
This is a ‘ripple’ counter meaning that a finite amount of time is required for all the stages to update once the count changes. Counters with more stages will require more time to reach a stable condition. The circuit is designed to minimize this time and a single clock is common to all stages. Thus, it should be able to operate properly with high clock rates. A four stage counter (16 bits) has been tested to a clock speed of 80 ms, or 12.50 Hz. Shorter counters will operate faster. A two stage counter operates at least to a 40 ms, or 25 Hz speed.
Following is the circuit diagram of one stage. The signals going to the next (higher) stage are all at the top. Note that the bits of the data bus are NOT shared between the stages, so a dotted line is shown as a reminder.
There are several inputs to the counter. There are four inputs that interact - two separate inputs for counting up and down, a LOAD input and a clock input. When either the up or down input is set, the counter will increase or decrease on the next rising edge of the clock. This change will ripple through the circuit to update all sections. If the load input is set, then the data present on the bus will be loaded into the counter on the next rising edge of the clock. The load input takes precedence over the up or down controls. If both the up and down inputs are high then the count will not change. There is an output enable control input. When this is high, the counter’s outputs will be presented to the data bus. It is assumed that the size of the counter does not exceed the size of the data bus. If that is not the case, additional circuitry will be required to select the different portions of the counter.
The bank labeled ‘L’ is the core of the counter. This holds the current count value and is essentially a latch circuit. It is programmed with the linear function. All clock inputs to each stage are connected together. This ensures that the outputs will change at the same time. The bank labeled ‘+/-1’ computes the next value to be loaded in the latch. The current value is input to one side (L) and the other side has the command input. This command incorporates both the UP and DOWN control in a single hex (analog) signal. This is done to greatly simplify the circuitry but requires the two controls to be combined through a D>A chip, or other means. The programming expects the UP control to be input as the bit3 and DOWN as bit2 on this input. These may be changed as needed but the bank’s programming must be modified accordingly. To clarify the programming, the +/- bank’s output will be equal to the latch output +1, when only the UP control is positive. The +/- bank’s output will be equal to the latch output -1, when only the DOWN control is positive. For all other values of the up/down input, the +/- bank’s output will be equal to the latch output, and no change to the latch will happen when its clock input rises. The ‘C/B’ bank determines whether a carry or borrow will be needed from the next higher stage. The latch output (of its current stage) goes into one of its inputs while the +/-1 function feeds into the other. This lets it detect whether the current stage will overflow or underflow with the next clock pulse and it will supply the +/-1 control to the next higher stage, accordingly. The discrete gates at the bottom of the schematic control the input to the latch. As long as the LOAD control is high, the +/-1 bank’s output is disconnected from the latch and the data bus is fed to the latch. On the next clock rising edge, this data will be loaded into the latch. The AND gate at the top of the diagram is a buffer to the data bus. The latch output is sent to the bus as long as the OUTPUT ENABLE control is high.
Options and Notes
- The NOT gate and the AND gate it feeds could be combined into a single memory bank, to save space.
- There are many other possibilities available with this setup. You could create +/-2 counts or even non-linear functions. This article will not cover those cases.
- If your system needs the UP count to take precedence over the DOWN count, that program is provided below. Also given is the opposing program (DOWN over UP). The main code assumes that if both are set, this indicates an error condition and no change will take place.
- If the counter does not need to be read by the bus, the top AND gate is not required and the physical layout will be simplified.
- It is possible to disable the +/-1 bank’s output differently and eliminate some gates, by incorporating the load control in the +1/-1 control. This is left as an exercise for the reader, if desired.
- Typically, a Program Counter only requires the UP function. In this case, that control may be binary (digital) and fed directly to the +/-1 bank. That bank’s program will be simplified and is also provided below.
- This counter could be operated in an asynchronous mode with one minor addition. Instead of using a system clock, the three (or two) control inputs may be ‘OR’d together, followed by a short delay. That signal would then be fed to the clock input to cause an update any time one of the control signals goes active. This may be desirable for a Stack Pointer or a Program Counter.
These are the ‘programs’ to be put into the several memory banks. They are provided here so they may be copied by the device running Survivalcraft and pasted directly in the game. The procedure to do this is described in the Memory Bank article. All programs assume the address inputs are assigned as described above. If they are swapped, the data matrix (grid) must be ‘inverted’. This is not covered here.
The ‘L’ bank has a basic linear function and uses only the first line: 0123456789ABCDEF
The ‘+/-1’ bank selects the next state of the latch. This assumes bit assignments as detailed above: 0123456789ABCDEF000000000000000000000000000000000000000000000000F0123456789ABCDE000000000000000000000000000000000000000000000000123456789ABCDEF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
For UP control dominance, use: 0123456789ABCDEF000000000000000000000000000000000000000000000000F0123456789ABCDE000000000000000000000000000000000000000000000000123456789ABCDEF0000000000000000000000000000000000000000000000000123456789ABCDEF0000000000000000000000000000000000000000000000000
For DOWN control dominance, use: 0123456789ABCDEF000000000000000000000000000000000000000000000000F0123456789ABCDE000000000000000000000000000000000000000000000000123456789ABCDEF0000000000000000000000000000000000000000000000000F0123456789ABCDE000000000000000000000000000000000000000000000000
For a binary (digital) UP ONLY bank, use: 0123456789ABCDEF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123456789ABCDEF0 This is the same as putting the first row (‘0’) as: 0123456789ABCDEF and the last row (‘F’) as: 123456789ABCDEF0
The ‘C/B’ bank determines the carry or borrow to the next stage: 0000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 This is the same as putting row ‘4’ as: 4000000000000000 and row ‘8’ as: 0000000000000008