Altifigence Academy

3 / 37 · Concept

Modules, ports and instances: connections as contracts

Compose combinational modules using named connections while checking single drivers and hierarchy boundaries.

A module boundary is not a clock boundary

A module groups ports and internal logic. A new instance does not automatically create a register or add a cycle. Two combinational modules in series remain a combinational path; their physical delays still add. A clocked register is an explicit storage boundary.

Write a port contract with direction, width, signedness, driver and valid time. The names below say which input is chosen, rather than relying on the reader to remember a positional order.

SystemVerilog
module select_word #(parameter integer W = 8) (
  input  logic [W-1:0] a, b,
  input  logic         select_b,
  output logic [W-1:0] y
);
  assign y = select_b ? b : a;
endmodule

module choose_and_increment (
  input  logic [7:0] a, b,
  input  logic       select_b,
  output logic [8:0] result
);
  logic [7:0] chosen;
  select_word #(.W(8)) select_u (
    .a(a), .b(b), .select_b(select_b), .y(chosen)
  );
  assign result = {1'b0, chosen} + 9'd1;
endmodule

select_word is the module type; select_u is the instance name. .a(a) connects the child port named a to the parent signal named a. The parameter override .W(8) is chosen when the design is elaborated; it is not a value sent through a run-time port.

Inspect every connection in both directions

chosen has one driver: the child’s y output. The parent reads it. Do not also assign chosen in another parent procedure. Using logic does not make conflicting drivers acceptable.

result is nine bits because incrementing 255 needs 256. The concatenation explicitly extends chosen before addition. With a=255, b=9, select_b=0, result is 256. With select_b=1 it is 10. Reducing result to eight bits would lose the first result’s carry.

Hierarchy, files and top selection

Both module definitions may be in one file or separate files. The compiler must receive both. The selected top is choose_and_increment; choosing select_word instead exercises a different design boundary. A missing child-module file is a source-list error, not proof that the port logic is wrong.

Prefer named connections in teaching and reusable designs. Positional connections can silently change meaning when a port list is edited. An unconnected input is not a deliberate 0. Explicitly connect constants or document intentionally unused outputs, and review the resulting tool diagnostics.

Avoid a feedback loop in which a combinational output ultimately drives its own input without storage. Following arrows through hierarchy is part of checking the design; module boundaries alone do not break such a loop.

Practice · Verify composition independently

Check (a,b,select_b)=(0,255,0), (0,255,1), (255,0,0), (255,0,1). Expected result values are 1, 256, 256 and 1. Then exhaust all 256 values of the selected input with both select values. Keep the unselected input different so an inverted selector cannot hide behind equal inputs.

For a reference model, choose an integer value from a or b, add one, and compare it with the nine-bit result after the combinational path settles. Do not read chosen from inside the DUT as the reference. That would miss a wrong child selection shared by the checker.

Finally add an output register as a separate exercise. State whether its reset is synchronous, when result becomes valid and which input edge each output represents. Adding that register changes the interface’s timing even when its arithmetic is unchanged.

Your choice applies to this browser. Change it any time using the footer.