CHIP DESIGN · COURSE

RTL Design with SystemVerilog

Turn cycle-accurate hardware requirements into portable, reviewable SystemVerilog RTL. The course begins with module contracts and tool boundaries, then derives exact packed types, expression sizing, combinational and sequential ownership, reset, parameters, generated structure, valid-ready backpressure, control/datapath partitioning, finite-state recovery, and bounded clock/reset crossings. Assertions, lint, synthesis reconciliation, parameter boundaries, and mutation-sensitive evidence close the loop. Every claim says whether it comes from language semantics, simulation, synthesis, timing analysis, or a later physical adapter.

Before this course: Completed Digital Logic & Boolean Reasoning and Computer Architecture Chapters 1–4. The course assumes binary representation, Boolean/combinational logic, registers, FSMs, synchronous timing, ISA state, datapaths, and multicycle control, but no prior HDL tool installation or verification framework.

COURSE FACTSStage, chapters, units, prerequisite, and outcome
Chapter 1

A module interface is a timed hardware contract

Objective: What must the port list alone cannot express? Answer by naming the hardware owner, update event, width, and one mutation that should fail the evidence.

A module boundary names values and direction, but a usable interface also states when each value is valid and which side owns changes. Register-transfer level design describes values transferred between named state elements on clock events and the combinational logic that derives next values. SystemVerilog source is not executed like an ordinary sequential program: simulators schedule events according to language semantics, while synthesis tools infer a bounded hardware structure from a supported subset. Every lesson therefore separates source meaning, simulated observation, inferred hardware intent, timing assumptions, and the evidence still required from lint, simulation, synthesis, constraints, and implementation.

The specification is: A synchronous incrementer accepts one 8-bit input when in_valid is high at a rising edge and publishes input+1 with out_valid exactly one cycle later; reset suppresses output validity. The invariant to derive is: Every accepted input creates exactly one matching output one cycle later, and no unaccepted cycle creates a valid output. Before writing a process, state the signal owner, bit width, signed interpretation, clock domain, reset state, update event, valid interval, illegal inputs, latency, throughput, and backpressure behavior. Then decide whether each output is continuously combinational, registered state, or protocol evidence. The failure boundary “Leaving latency implicit lets a testbench sample combinational input+1 in the acceptance cycle while the implementation registers it for the next cycle.” is retained because a clean compile or attractive waveform can otherwise conceal the wrong circuit.

Every accepted input creates exactly one matching output one cycle later, and no unaccepted cycle creates a valid output. This conclusion applies to the stated synthesizable model and clock/reset assumptions; it is not by itself proof of a particular cell netlist, clock frequency, area, power, CDC closure, FPGA behavior, or fabricated silicon.

At an accepting edge, capture the 8-bit input and one valid bit into module-owned registers. At derivation step 1, identify whether the value is read from pre-edge state, computed by combinational logic, or published at an active edge. Track full width and signedness before applying an operator, and state which assignment or handshake transfers ownership.

Combinational addition derives the widened or wrapped result according to the declared 8-bit policy. At derivation step 2, identify whether the value is read from pre-edge state, computed by combinational logic, or published at an active edge. Track full width and signedness before applying an operator, and state which assignment or handshake transfers ownership.

At the following edge, publish the retained result and valid identity unless reset overrides the state. At derivation step 3, identify whether the value is read from pre-edge state, computed by combinational logic, or published at an active edge. Track full width and signedness before applying an operator, and state which assignment or handshake transfers ownership.

Trace reset low, then accepted inputs 7 and 255 on consecutive edges with 8-bit wrap. First write the expected values immediately before and after each relevant event. Then describe the smallest synthesizable structure that can own those values.

  1. After accepting 7, current output is still prior invalid state while 8 is retained for next publication. At trace step 1, record raw bits and interpreted value, active process, event region or edge, enable and reset status, and whether the result is tentative or architecturally observable at the interface.
  2. At the next edge publish 8 while accepting 255 and retaining wrapped 0. At trace step 2, record raw bits and interpreted value, active process, event region or edge, enable and reset status, and whether the result is tentative or architecturally observable at the interface.
  3. At the following edge publish 0 with valid high. At trace step 3, record raw bits and interpreted value, active process, event region or edge, enable and reset status, and whether the result is tentative or architecturally observable at the interface.

Result: Accepted sequence 7,255 produces valid outputs 8,0 one cycle later each. The result is accepted only when the trace, assertion, and inferred-structure expectation agree. If synthesis is not run, say “simulation contract only”; if timing is not constrained and analyzed, do not claim a frequency.