There are a whole bunch of clever and interesting ways that you can
drive the d12
pin to determine what sort of sequential
logic element is behind q1
and q2
. Most
everyone caught on to the basic ideas: assert d12
near
a rising edge, look for a response; assert d12
near a
falling edge, watch what happens; pulse d12
high during
the positive or negative cycle of the clock, watch the result. The
waveform below shows many of these situations.
Marked in the waveform are four points where we can deduce information about the logic elements:
a Are we driving a positive clocked latch? If
so, then the latch should follow d12
at this edge.
q2
does, so we guess that it's a positive clocked
latch.
b Is either element a negative edge trigged
flip-flop? If so, then at this falling clock edge, with
d12
asserted, the flip-flop should change from 0 to 1.
q1
doesn't change, so it's not a negative edge triggered
device.
c What about positive edge triggered devices?
d12
is asserted, and here is a positive edge. In fact,
q1
does go high when this edge comes along, so
q1
is probably a positive edge triggered device.
d Do we have a negative clocked latch? If we
had such a device, it would reflect changes in d12
when
the clock was low. d12
changes here, but
nothing happens on our devices, so they aren't negative clocked
latches.
The device has an asynchronous clear which resets the output to 0 whenever clr is 1. The output remains 0 until the input is high at a positive edge of the clock. Thereafter, the output will remain high, regardless of what the input does. The 1 on the input has been "caught".
MODULE shift1 interface (di, sr, sl, s0, s1, clk -> z); TITLE 'One-bit shift register' "Inputs di, sr, sl, s0, s1 pin; clk pin; "Output z pin istype 'reg, buffer'; "Alias EQUATIONS z.clk = clk; WHEN ( s1 & s0) THEN z := di; ELSE WHEN ( s1 & !s0) THEN z := sr; ELSE WHEN (!s1 & s0) THEN z := sl; ELSE WHEN (!s1 & !s0) THEN z := z.fb; END
MODULE shift4 interface (clk, i3..i0, s2..s0 -> q3..q0); TITLE 'Universal 4-bit shift register' clk, i3..i0, s2..s0 pin; q3..q0 pin istype 'com'; shift1 interface (di, sr, sl, s0, s1, clk -> z); sh3..sh0 functional_block shift1; EQUATIONS [sh3..sh0].clk = clk; [q3..q0] = [sh3..sh0].z; [sh3..sh0].di = [i3..i0]; sh3.sr = (sh3.z & s2) # (sh0.z & !s2 & !s1); sh2.sr = sh3.z; sh1.sr = sh2.z; sh0.sr = sh1.z; sh3.sl = sh2.z; sh2.sl = sh1.z; sh1.sl = sh0.z; sh0.sl = !s2 & sh3.z; [sh3..sh0].s1 = s0; [sh3..sh0].s0 = (s2 & s1) # ((s2 $ s1) & !s0); ENDUnfortunately, ABEL also lets you have very cumbersome code. Many of you had in your EQUATIONS block a big
WHEN THEN ELSE ...
block that switched on the shift control signals s2..s0
.
Certainly, this strategy is not wrong, but probably not ideal. In
particular, it is easy to make mistakes with this approach; there are
scores of lines of code, anyone of which you might mistype. Further,
it is difficult for someone to look over the code and discern that the
blocks are, in fact, closely related (i.e., logical shift left and
arithmetic shift left both shift left).
Many of you who opted for the ABEL approach built separate modules for
flip-flops. Again, this strategy was not incorrect, but probably
excessive. To create a flip-flop in an ABEL module, you need only
declare a pin to be a reg
:
q3..q0 pin istype 'reg, buffer';
sl
and sr
blocks are on opposite sides.
This schematic uses an additional ABEL block to generate the miscellaneous control signals:
MODULE control interface (s2..s0 -> c1..c0, m0_0, m3_0, m3_1); TITLE 'Shifter control' "Inputs s2..s0 pin; "Outputs c1..c0 pin istype 'com'; " Shift cell control m0_0 pin istype 'com'; " Control for bit 0 mux m3_0, m3_1 pin istype 'com'; " Control for bit 3 mux "Aliases s = [s2..s0]; c = [c1..c0]; m3 = [m3_1..m3_0]; hold = 0; shiftLeft = 1; shiftRight = 2; load = 3; EQUATIONS WHEN (s == 0) THEN c = hold; "Hold ELSE WHEN (s == 1) THEN c = shiftRight; "Circular shift right ELSE WHEN (s == 2) THEN c = shiftLeft; "Circular shift left ELSE WHEN (s == 3) THEN c = shiftRight; "Logical shift right ELSE WHEN (s == 4) THEN c = shiftLeft; "Logical shift left ELSE WHEN (s == 5) THEN c = shiftRight; "Arithmetic shift right ELSE WHEN (s == 6) THEN c = shiftLeft; "Arithmetic shift left ELSE WHEN (s == 7) THEN c = load; "Parallel load WHEN (s == 2) THEN m0_0 = 1; "Use out3 ELSE m0_0 = 0; "Use 0 WHEN (s == 1) THEN m3 = 0; "Use out0 ELSE WHEN (s == 5) THEN m3 = 1; "Use out3 ELSE m3 = 2; "Use 0 ENDRegardless of the approach you took, the waveforms for the solution should resemble those shown below:
(For more information about using buses in Synario, see Tip #4 on the Synario Tips page).
MODULE graycntr interface(clk, reset, en -> c2..c0); TITLE 'Gray code counter' "Inputs clk, reset, en pin; "Outputs c2..c0 pin istype 'reg, buffer'; "Alias c = [c2..c0]; EQUATIONS c.clk = clk; WHEN (en) THEN { WHEN (reset) THEN c := ^b110; ELSE WHEN (c == ^b000) THEN c := ^b001; ELSE WHEN (c == ^b001) THEN c := ^b011; ELSE WHEN (c == ^b011) THEN c := ^b010; ELSE WHEN (c == ^b010) THEN c := ^b110; ELSE WHEN (c == ^b110) THEN c := ^b111; ELSE WHEN (c == ^b111) THEN c := ^b101; ELSE WHEN (c == ^b101) THEN c := ^b100; ELSE WHEN (c == ^b100) THEN c := ^b000; } ELSE c := c; ENDThe notation
^b001
is an alternate notation for a binary
value.Several solutions were presented where the equations for each c2, c1, and c0 were simply equations from the previous values of c. This certainly is a valid approach, but probably not the best one. In particular, if you have used a K-map to derive these equations by hand, then you are not using the tools to their full capacity. The motivation to a Hardware Description Language such as ABEL is to allow the designer to state his or her intentions at a high level and let the tools translate these intentions into equations.
A sample waveform for the Gray code counter is:
Besides writing ABEL for the Gray code counter, you were also asked to draw a state machine for the device, and show how the counter would be mapped onto an EO320. A state machine for the counter is:
The most common mistakes on the state machine were forgetting to label
the transitions, or forgetting to show the transitions for when
en
was low.
Finally, we have the EO320 fuse map. If you peeked inside the .jed file that Synario created, you could see exactly which fuses were made or blown. However, you could also have gotten the gist of the story from looking at the equations that Synario produced. One thing to watch out for on the Fuse Map is that the top minterm on each output pin is not part of the pin's value. Instead, this minterm controls the tristate buffer associated with the pin.
(See following page)