Skip to the content.

The “CUPL” code for my clock module

The CUPL source for the ATF16v8 module is in this repo here: be8clock.pld

The following text explains the functionality implemented in this file and how it works.

What the module does

The functionality implemented in this module includes:

Implementation details

Schematic

The following schematic reflects the logic built by the CUPL program, and can be used as reference.

SPLD logic schematic

Numbers correspond to pin numbers in the U2. You can open the image in a new tab to zoom in.

Input signals

The input pins are defined as follows:

PIN 1 = clk ;    /* 555 based clock */
PIN 2 = clki ;    /* tied to pin 1; clk can not be used in formula */
PIN 3 = push ;    /* push-button: trigger clock pulse */ 
PIN 4 = !mman ;   /* toggle set to manual */ 
PIN 5 = !mauto  ; /* toggle set to auto */ 
PIN 9 = hlt ;     /* halt clock */ 

Pin 1 is the standard clock input for the ATF16V8 flip-flops. However, the value on pin 1 can not be used as an input for logic gates if it is used as a clock, so the input clock is connected to pin 2 (both pins are bridged together).

Pin 3 is attached to the push buttons (which defaults to a low value with a 10K pull-down, and pressing it drives it to Vcc).

Pins 4 and 5 are attached to the two end terminals of the mode switch. The common point of the switch is attached to the ground, and both switches have a 10K pull-up. This means that one side will go high and the other low when switching. The names of the input signals are mman (“mode=manual”, for single-step) or mauto (“mode=automatic” for running oscillator).

The exclamation mark in the pin definitions indicates that the signals are active-low. Note that in logic formulas used later, using a name as mauto will be interpreted as “the signal mauto is active” (i.e. low), not to be confused with “the signal mauto is high”. CUPL focuses on providing formulas based on logic and leaving the active-high/active-low decision as implementation details in the pin definitions.

Pin 9 is the HLT (halt) signal.

The ATF16V8B has three-state functionality that I’m not using. The “output-enable” pin is always pin 11 and needs to be defined in the CUPL file:

PIN 11 = !oe ;

Switch debouncing

The mode switch can have (as any mechanical switch) some bouncing, so the circuit can not rely directly on pins 4 and 5 to identify the mode. There could be states while the switch is moving that none of them are active. I used the PLD cells to implement a SR-latch (set/reset latch) that is set/reset based on the mode. This ensures that a single mode is selected at any time. When the switch gets a known position, that event is used as a set or reset signal. While the switch travels or bounces, the latch will keep its current state.

Note that the state of a set/reset latch can be defined as the following logic formula: Q' = S # (!R & Q).

Notes:

With that, we can build the following pieces of the CUPL file defining the latches as formulas.

PIN 14 = deb_mman ; /* debounced mman */
PIN 15 = zero     ; /* shared ground for indicator LEDs */
PIN 16 = deb_mauto ;  /* debounced mauto */

/* SR-latch logic (set priority). Q' = S # (!R & Q) */
deb_mauto = mauto # (!mman & deb_mauto);  
deb_mman = !deb_mauto;

zero = 'b'0;

The name deb_mauto means “debounced mode=automatic”. An active mauto signal will be the “set” operation in the latch. An active mman signal will be the “reset” operation.

The name deb_mman means “debounced mode=manual”. I don’t need another latch for this signal. It’s always the opposite of deb_mauto. Doing this guarantees that consistently exactly one of the deb_xxx signals will be active at any given time.

These two signals are sent to pins 14 and 16 which are used for the mode indicator LEDs (the two small green LEDs). Pin 15 is set to a value which is always low. This is a small hack to have a “ground” value for the LEDs, which reduces a bit the wiring/soldering needed.

Single step button

The single step push button uses debouncing, and also relies on a SR-latch called deb_push. The mechanics of this latch are a bit different than before.

Pushing the button while on single step mode acts as a “set” signal. However releasing is not a reset (otherwise the bounces will just toggle the latch quickly). Instead, the next clock rising edge after the button is pushed will set active one of the PLD flip-flops called ff_hold. The output of ff_hold will act as the reset signal, which will clear deb_push. When deb_push is low, ff_hold will go low the next rising edge.

The formula definition we used for SR-latches gives priority to “set” signals. If both the “set” and “reset” are high, the latch will be set and ignore the reset. That means that if ff_hold is already set, but the button is still pushed, the latch will stay active (and thus, ff_hold will too).

Our clock output will be the result of deb_push # ff_hold. So the clock will be active as soon as the button is pressed, and will keep active while it’s pressed (because of deb_push). Once it’s released, the next rising edge will bring ff_hold up (if it wasn’t already due to a long push). That will reset deb_push but keep ff_hold up for a full clock cycle.

If you press the button very very briefly, the clock output will stay for an amount shorter than a cycle (until the next rising edge), and then a full extra cycle, so a total which is at least one cycle and less than two cycles.

To define this, we need both signals. Because of the design of the ATF16V8, we need to assign a signal to an output pin if we want to use one of the flip-flops, and also if we want to feed an output signal back into the chip (which is required in a SR-latch). Rather than defining a PIN, you can define those as PINNODE (which means “use this PIN, but this is not a real output”). In practice it’s the same (and the signal in fact comes out of the pin), but it documents the intent:

PINNODE 17 = deb_push ;  /* debounced push */
PINNODE 19 = ff_hold ; /* hold while waiting for clock after push */

/* SR-latch logic. set priority */
deb_push = (push & deb_mman) # (!ff_hold & deb_push); 
ff_hold.d = deb_push;

The ff_hold.d syntax states that ff_hold is a D flip-flop (which makes it automatically clocked with the CLK pin of the PLD).

Signal output

The main outputs are:

PIN 12 = clko ;   /* clk output */ 
PIN 13 = clkled ; /* clk led indicator */ 

...

clkled = clko ;
clko = !hlt & ((clki & deb_mauto) # (deb_mman & (deb_push # ff_hold)));

Both pins produce the same signal and are interchangeable. They are repeated for convenience putting the board together.

The output signal formula contains the following parts:

Possible adjustments

If you desire slightly different functionalities, these are some simple changes that you can make: