Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Quick Start: Your First Green Build
  • Part 1: How Chips Get Made6
  • Part 2: Your Workstation5
  • Part 3: Specify and Architect3
  • Part 4: The Design Loop6
  • Part 5: The Verification Ladder6
  • Part 6: Automation and Reproducibility5
    • Makefile for the Loop
    • Exit Codes and Pass Markers
    • CI Smoke Test
    • Pinning Tool Versions
    • Smoke vs Nightly
  • Part 7: Hand-Off to the Back-End3
  • Part 8: When Things Go Wrong3
  • Part 9: Project and Next Steps3
  • Reference4
Loading lesson

‹Part 6: Automation and Reproducibility
  1. Topics
  2. Start Here: RTL and Verification
  3. Part 6: Automation and Reproducibility
  4. CI Smoke Test

Part 6 · Automation and Reproducibility · Working (W)

CI Smoke Test

Run the loop on a clean machine for every change: the CI smoke-test workflow, what each part of the file asks for, and what it honestly does not yet pin down.

On this page

    Note

    Level: Working (W) · Answers: How do you make sure every change is checked automatically, even when you forget?

    Before this: Exit Codes and Pass Markers

    It is Friday evening and you push a small cleanup before logging off. The change looks trivial, so you skip the local run and head home. On Monday the team finds the design broken, and the fix takes an hour that a three-minute check would have saved.

    How do you make sure every change is checked automatically, even when you forget?

    The answer is continuous integration, universally shortened to CI: a service that runs your checks on a clean machine for every push and every pull request, which is a proposal to merge one branch into another. You stop relying on memory, and the machine stops forgetting.

    A clean machine runs your checks for every change

    Your laptop is a comfortable liar. It holds old build files, leftover environment settings, and tools installed months ago in ways nobody recorded. A check that passes there may pass because of that history rather than because of your change.

    CI removes the comfortable parts. Each run starts from a fresh machine image, installs the tools from scratch, checks out your exact change, and runs the loop. When that run is green, the result belongs to the change alone, and anyone on the team can reproduce it by running the same commands.

    Read the workflow file

    The workflow is written in YAML, a configuration format where each line is a key followed by a value and indentation shows structure. Two spaces deeper means inside the line above; get the indentation wrong and the key lands in the wrong place. Read the project's file below. It is thirteen lines, and each one is explained after it.

    Diagram
    name: RTL smoke
    on: [push, pull_request]
    jobs:
      smoke:
        runs-on: ubuntu-24.04
        steps:
          - uses: actions/checkout@v4          # course note: pin to a verified commit SHA
          - name: Install tools
            run: sudo apt-get update && sudo apt-get install -y iverilog verilator yosys make
          - name: Report tool versions
            run: make check-tools
          - name: Lint, simulate, synthesize
            run: make all

    This is the project's smoke-test workflow: four steps on a fresh machine, ending in the same full loop you run locally.

    Which step runs first and what the machine reports

    Read the picture below from top to bottom. Each box is one stage of the run, and the last box splits into the two possible endings. The labels under the boxes say what the machine actually does at each stage.

    Follow the boxes from the push at the top to the final step: only when every step exits zero does the run end green, and any nonzero exit ends it red.

    What each part of the file asks for

    The name line gives the run its display name: RTL smoke. The on line lists the events that start a run: every push and every pull_request. Nothing about this file runs on a timer or by hand; a change arriving is what wakes it up.

    One job called smoke runs on a fresh Ubuntu 24.04 machine, through four steps in order: checkout fetches your change, install fetches the simulator, the linter, and the synthesis tool, versions records the tool versions with make check-tools, and the final step runs make all.

    A step that exits nonzero stops the job immediately and marks it red. That fail-fast behavior is the whole enforcement mechanism: the counts_by_two failure from the previous lesson would stop the final step, and no green badge would follow. Later steps never run after a failure, so a red run always names the first thing that broke.

    The final step runs the loop you already know

    The last step runs the same command you ran locally in the previous two lessons. Here is what that command shows on the good design:

    Diagram
    # captured terminal output
    $ make all 2>&1 | grep -E '^(PASS|iverilog|vvp|verilator|yosys)' | cut -c1-110
    verilator --lint-only -Wall --top-module mini_controller rtl/mini_controller.sv
    iverilog -g2012 -Wall -s tb_mini_controller -o build/sim.vvp rtl/mini_controller.sv tb/tb_mini_controller.sv
    PASS: mini_controller
    yosys -Q -T -p 'read_verilog -sv rtl/mini_controller.sv; hierarchy -check -top mini_controller; proc; opt; che

    This output is the local run of the workflow's final step, measured with GNU Make 3.81 on macOS: the linter line, the compile line, the verdict line starting with PASS:, and the synthesis line. The project also passes the same loop on Ubuntu 24.04 with GNU Make 4.3 and that distribution's own packages: Icarus 12.0, Verilator 5.020, and Yosys 0.33.

    How this was checked

    This workflow file has not been run on a hosted CI service for this course. The evidence above is local: the project was run on macOS and inside an Ubuntu 24.04 container with that distribution's own packages, where make all passed. Treat the workflow as reviewed but unexecuted until you watch it run on your own repository.

    In your own repository this file lives at .github/workflows/rtl-smoke.yml, and the hosting service discovers it there automatically.

    Predict first You push a change that only edits a comment. Which steps of the workflow still run?

    All of them. CI never skips steps for changes that look safe. The full loop reruns on the fresh machine and reports green against the change alone.

    Break it on purpose: push the counts_by_two bug

    Imagine the counts_by_two mutant from the previous lesson reaching the workflow. The first three steps pass: the code is fetched, the tools install, the versions are reported. Then the final step runs the simulation, the testbench reports mismatches, the verdict gate finds no verdict line, and make exits 2:

    Diagram
    # captured terminal output
    $ make sim > /dev/null 2>&1; echo "make sim exit status with a counts_by_two bug: $?"
    make sim exit status with a counts_by_two bug: 2

    This output is the local form of the red run, measured with GNU Make 3.81 on macOS: the step that runs the loop fails, so the job stops and the run is marked red. The fix is the same as locally: restore the design, push again, and watch the new run go green.

    The log ends with the tool lines, the mismatch reports, and the make error. A red run always names the first thing that broke, so read a CI log from the first failure, not the last line.

    What this baseline does not yet pin down

    The file works, but three of its choices can move under you. The runner label names an image family rather than an exact copy, and the install step takes whatever tool versions the package mirror offers that day. The checkout step is referenced by a tag, which can be moved to different code after you read it.

    Each of those is a way for today's green run to differ from next month's without any change from you. The next lesson shows what can be pinned down: exact tool versions, verified action code, and a recorded environment, so a rerun means the same run.

    Three ways teams waste a smoke test

    • A workflow that installs tools but never runs the tests. The log shows a successful install and the badge goes green, while no check ever ran. End every workflow with the step that runs the loop, and read a green badge as a statement about that step.

    • Merging despite a red build. A red run that gets merged anyway teaches the team that red is advice. Treat red as a closed gate: fix the change or fix the check, then rerun before merging.

    • Letting unpinned versions drift. When the runner image or the tool packages update silently, a new failure may belong to the environment rather than the change. Record versions in the log with the versions step, and pin what the next lesson shows you to pin.

    Every change gets checked, even the trivial one

    Rule: every push gets a fresh machine, the full loop, and a red or green answer.

    Check yourself The counts_by_two bug reaches the workflow. Which step turns red, and what does the learner see?

    The fourth step, Lint, simulate, synthesize, turns red. The first three steps pass: checkout, install, and versions all succeed. The log ends with the simulation tool lines, the mismatch reports, and the make error from the failed recipe, and the run is marked red at that step.

    Check yourself Name two things in this baseline that can change without any edit from you.

    The runner image behind the Ubuntu label, which the host updates over time, and the tool versions the package installer fetches, which track whatever the mirror offers that day. The checkout tag is a third: a tag can be moved to different code after you first read it.

    Check yourself Where does this file live in your own repository, and why there?

    At .github/workflows/rtl-smoke.yml. The hosting service scans that directory for workflow files on every push and pull request, so placing the file there is what connects your change arriving to the checks running.

    Interview

    Asked: "What belongs in a pull-request smoke check versus a nightly run?"

    Weak answer: Everything should run on every push so nothing is ever missed.

    Strong answer: The pull-request check holds the fast loop that gates merging: lint, the full simulation, and the synthesis check, finishing in minutes so authors get an answer before context goes cold. The nightly run holds what is too slow or too broad to gate on: long random-seed sweeps, coverage collection, and full regression sets. Smoke answers whether this change broke anything; nightly answers how much the project has proven overall.

    Follow-ups: (1) How long is too long for a smoke check? (2) What do you do when the nightly run fails but smoke stayed green?

    Key takeaways

    • CI runs the full loop on a fresh machine for every push and pull request, so no change depends on anyone remembering to check it.

    • The workflow checks out the change, installs tools, records versions, and runs make all, failing fast at the first nonzero step.

    • Runner labels, package versions, and action tags can drift, so record versions now and pin them next.

    Keep going

    Next: Lesson 6.4, Pinning Tool Versions. The smoke test runs everywhere the same way, but the tools underneath can still drift. The next lesson pins them down.

    Related topics

    • UVM: Regression Infrastructure

    • Previous: Exit Codes and Pass Markers

    Previous

    32 / 47

    Next: Pinning Tool Versions

    Up next

    Up nextPinning Tool Versions

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Makefile for the Loop
    • Smoke vs Nightly