Latch
A D-type latch captures a snapshot of a running counter when a button is held. When the button is released, the latch holds its last captured value and the LEDs freeze.
Modules
latch_test
The module takes a clock, power-on reset, active-low reset button, a latch-enable button (btn), and outputs 6 LEDs.
The ASYNCHRONOUS block does three things:
- Combines
porandrst_ninto an active-lowresetwire. - Drives the D-latch:
display_buffer <= btn : ~counter[26:21]. Theenable : datasyntax meansbtnis the gate — when high, the inverted upper counter bits flow through; when low, the latch holds. - Outputs
leds <= { btn, display_buffer[4:0] }— the MSB LED shows the button state, the lower 5 LEDs show the latched value.
The SYNCHRONOUS block increments a 27-bit counter on every clock cycle, identical to the counter example.
The key declaration is LATCH display_buffer [6] D — an explicitly declared 6-bit D-type latch. The width and type are part of the declaration, not inferred from context.
Project Files
Two project files target the Tang Nano 20K and 9K. Both map two buttons — one for reset, one for latch enable — and six LEDs. Button polarity is inverted between boards.
jz
@project(CHIP="GW2AR-18-QN88-C8-I7") LATCH_EXAMPLE
@import "latch.jz"
CLOCKS {
SCLK = { period=37.04 }; // 27MHz clock
}
IN_PINS {
SCLK = { standard=LVCMOS33 };
DONE = { standard=LVCMOS33 };
KEY[2] = { standard=LVCMOS33 };
}
OUT_PINS {
LED[6] = { standard=LVCMOS33, drive=8 };
}
MAP {
// System Clock
// 27MHz
SCLK = 4;
// 2 BUttons
// High = Closed
// Low = Open
KEY[0] = 87;
KEY[1] = 88;
// 6 LEDs
// High = OFF
// Low = ON
LED[0] = 15;
LED[1] = 16;
LED[2] = 17;
LED[3] = 18;
LED[4] = 19;
LED[5] = 20;
// DONE can be used as a POR signal
// Low = programming ongoing
// High = programming successfully
DONE = IOR32B;
}
@top latch_test {
IN [1] clk = SCLK;
IN [1] por = DONE;
IN [1] rst_n = ~KEY[0];
IN [1] btn = KEY[1];
OUT [6] leds = LED;
}
@endprojjz
// Latch example — demonstrates a D latch.
//
// A 27-bit counter free-runs at the clock rate. Six LEDs show the
// D latch output:
//
// leds[5] — raw btn state (direct passthrough).
// leds[4:0] — D latch (display_buffer[4:0]). While btn is held,
// the latch is transparent and the LEDs follow
// ~counter[26:22] (inverted upper counter bits).
// Releasing btn freezes the pattern.
//
// Button behavior:
// Hold — latch is transparent, LEDs track counter.
// Release — latch holds its last value, LEDs freeze.
@module latch_test
PORT {
IN [1] clk;
IN [1] por;
IN [1] rst_n;
IN [1] btn;
OUT [6] leds;
}
WIRE {
reset [1];
}
REGISTER {
counter [27] = 27'b1;
}
LATCH {
// Explicit storage for the 6-bit LED pattern
display_buffer [6] D;
}
ASYNCHRONOUS {
reset = por & rst_n;
display_buffer <= btn : ~counter[26:21];
leds <= { btn, display_buffer[4:0] };
}
SYNCHRONOUS(CLK=clk RESET=reset RESET_ACTIVE=Low) {
counter <= counter + 27'b1;
}
@endmodJZ-HDL Language Features
Explicit latch declaration. In Verilog, latches appear silently whenever an always @(*) block has an incomplete if or case — the designer never asked for a latch, but one appears in the netlist. These accidental latches are a top source of synthesis bugs, and tools may only flag them as warnings.
JZ-HDL requires latches to be declared in a LATCH block with a name, width, and type. The gated assignment syntax (enable : data) makes the enable condition visible at the point of use. If no latch is declared, the compiler will not infer one — incomplete assignments in ASYNCHRONOUS blocks are compile errors. Every latch in a JZ-HDL design exists because the designer put it there intentionally.