Skip to main content

Module reading_systemverilog

Module reading_systemverilog 

Source
Expand description

A reading guide for the SystemVerilog constructs used by the backend.

§Reading the SystemVerilog

This page explains every language pattern needed to read the fast backend. It is intentionally specific to this codebase rather than a general language tutorial.

§Modules and elaboration

A module is a hardware component. Its parameter list is evaluated when the design is elaborated, before synthesis. Its port list is the physical signal interface. Instantiating a module creates hardware; it is not a software function call.

module example #(
    parameter TAG_BITS = 16
) (
    input wire clk,
    input wire [TAG_BITS-1:0] tag_in,
    output reg [TAG_BITS-1:0] tag_out
);

TAG_BITS changes signal and storage widths. input and output describe direction at the module boundary. A packed range such as [254:0] is one 255-bit vector. An unpacked range after a name, such as state [0:15], is an array of sixteen elements.

The backend has no SystemVerilog package imports and no preprocessor `include dependencies. Build scripts pass all module files to the HDL tool, which resolves instantiated module names during elaboration.

§Wires, registers, and assignments

wire represents a continuously driven connection. assign creates combinational logic that is always active:

assign ready_in = !busy;

reg means a variable assigned by an always block. In this code it may synthesize either to a flip-flop or to combinational logic depending on the block that drives it. The keyword does not by itself guarantee a register.

always @* is combinational. Every output assigned in such a block must receive a default before conditional overrides, or simulation can infer a latch. The arbiters use the pattern “default to not found, scan candidates, retain the first match.”

always @(posedge clk) is sequential. Assignments with <= are nonblocking: all right-hand sides observe the pre-edge state and all left-hand sides update together after the edge. This is why a valid bit and its data must travel through matching registers.

Reset is synchronous and active high inside the cryptographic modules. The AXI shell receives active-low ap_rst_n and creates areset = ~ap_rst_n.

§Handshakes

Input streams use ready/valid:

accept on a rising edge when valid_in && ready_in

The producer must hold data stable while valid is high and ready is low. Most arithmetic outputs have valid_out but no ready_out; consumers must provide enough buffering for every result pulse. Tags are metadata delayed beside the data so out-of-order internal completion can be associated with the request.

start/ready is the equivalent single-transaction convention used by the iterative SHA and legacy scalar modules. A request starts on start && ready.

§Generate loops and inferred resources

generate and genvar replicate hardware at elaboration. Four loop iterations around radix51_field_mul_pipe create four physical multipliers. An ordinary procedural for inside a clocked block can also unroll into parallel hardware when its bounds are constants.

Attributes communicate synthesis intent:

AttributeMeaning here
(* use_dsp = "yes" *)Ask Vivado to map fixed products or MACs into DSP48E2 cells
(* ram_style = "distributed" *)Prefer LUTRAM for a small queue or banked context store
(* ram_style = "block" *)Prefer block RAM
(* rom_style = "block" *)Prefer block RAM for a read-only table

They are requests, not proofs. The Vivado utilization report is the proof of what was actually inferred.

§Functions

A SystemVerilog function automatic is combinational logic inlined at each use site. “Automatic” gives each invocation private temporary storage during simulation. It does not create a shared callable hardware unit. The signer uses functions for byte reversal, block-word construction, digest repacking, and key clamping. SHA uses functions for rotations and sigma transforms. The active field multiplier uses weighted to multiply wrapped coefficients by 19.

§Memories and initialization

$readmemh(file, memory) initializes a simulation memory from hexadecimal text. For synthesis, multicomb_scan_bank uses AMD xpm_memory_sprom with MEMORY_INIT_FILE; the .mem files therefore remain required build inputs. The packaging script adds them to the IP rather than relying on an incidental working directory.

The SYNTHESIS conditional selects XPM block ROMs in Vivado and ordinary arrays in simulation. This is a vendor-specific leaf boundary inside otherwise plain SystemVerilog.

§Bit and byte order

Packed Ed25519 values use the low bits for the first little-endian bytes. SHA-512 words are big endian. reverse_bytes64 converts each 64-bit lane when building a SHA block. SHA state words are packed from the most significant end of the 512-bit state vector. A packed signature is {S, R}: R occupies bits 255:0 and S occupies bits 511:256, yielding the byte sequence R || S when written as a little-endian 512-bit record.

§Simulation-only checks

Code under `ifndef SYNTHESIS is omitted from hardware. The point codec uses this region to terminate simulation if a result queue overflows. $error, $display, and $fatal are diagnostic operations, not cryptographic logic.