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
    • Shell Survival Kit
    • Files, Paths and Layout
    • Git: Save, Compare, Undo
    • Installing and Checking Tools
    • Reading Tool Messages
  • Part 3: Specify and Architect3
  • Part 4: The Design Loop6
  • Part 5: The Verification Ladder6
  • Part 6: Automation and Reproducibility5
  • Part 7: Hand-Off to the Back-End3
  • Part 8: When Things Go Wrong3
  • Part 9: Project and Next Steps3
  • Reference4
Loading lesson

‹Part 2: Your Workstation
  1. Topics
  2. Start Here: RTL and Verification
  3. Part 2: Your Workstation
  4. Files, Paths and Layout

Part 2 · Your Workstation · Foundation (F)

Files, Paths and Layout

Where each file of the mini_controller project lives, why generated output stays out of version control, and what compile order means.

On this page

    Note

    Level: Foundation (F) · Answers: Where does each file go, and which files should never be saved?

    Before this: Shell Survival Kit

    Where does each file go, and which files should never be saved?

    You open the course example and find ten kinds of files spread over eight folders. Every one of them has a reason to sit exactly where it sits. Learn the reasons once and every hardware project you meet will look familiar, because they all answer the same two questions: what did a human write, and what did a tool produce?

    The example is mini_controller, a 4-bit event counter: it counts input events up to 15, then wraps to 0. You get it as a folder named mini-controller/ from the course download, described below. Its folders are rtl, tb, model, docs, scripts, tools, mutants, and github-workflows, plus a Makefile and a .gitignore at the root. The build/ folder does not ship with the project: make creates it on your machine when you compile.

    Get the example project

    Download start-here-examples.zip and unpack it. On macOS, double-click it in Finder, or in a terminal run unzip start-here-examples.zip; on Ubuntu and WSL, install unzip first if it is missing (sudo apt install unzip). You get a folder start-here-examples/ holding mini-controller/ and pulse-counter-starter/. Then cd start-here-examples/mini-controller and run pwd to confirm where you stand. Every make command in the course runs from that folder.

    Source is what humans write; generated is what tools produce

    Source files are the project. A human wrote them, a human reviews them, and version control saves them. The design in rtl/, the testbench in tb/, the golden model in model/, the specification in docs/, the helper scripts, the tool versions, the mutants, and the CI workflow are all source. If the disk lost everything except these, a fresh machine could rebuild the rest.

    Generated files are the exhaust. The simulator writes compiled output, logs, and waveforms; synthesis writes its own logs. These files matter for today debugging, and they are worthless next week, because any machine can reproduce them bit for bit from source. Saving them in version control bloats every download and guarantees stale copies: your teammate opens your old waveform and mistakes it for the current behavior.

    The rule between the two is one way. Source flows into tools, tools emit generated files, and generated files never flow back. You never edit a generated file to fix the design, the way you never edit a printed page to fix a book. When generated output looks wrong, you fix the source or the command and regenerate.

    One folder per role, so every path tells you its job

    Each folder owns one role, and the path of a file states that role before you open it. rtl/ holds the design, the register-transfer level description of the hardware: registers and the logic between them. tb/ holds testbenches, the scaffolding that drives the design and checks it. model/ holds the golden model, an independent description of correct behavior the testbench compares against. docs/ holds the specification the design was written against.

    The remaining folders support the loop: scripts/ holds helper commands, tools/ records the tool versions, mutants/ holds deliberately broken design copies for testing the testbench, and github-workflows/ holds the continuous integration (CI) workflow, the automation that reruns the loop on every change. The Makefile at the root is the control panel: one short name per task, such as make sim, reruns a whole chain of commands.

    The figure below draws the full layout as two columns. The left column is everything a fresh checkout contains; the right column is everything the tools add on your machine. Dashed boxes and made tags mark the difference twice, so it never depends on shade alone.

    The real mini_controller layout split by fate. Look at which column each path sits in: source on the left is kept, tool output on the right is regenerated and ignored.

    The ignore file states what version control must skip

    The .gitignore file at the project root lists the paths version control must never save. It is source itself: a human wrote it, and it ships with the project so every machine ignores the same files. The listing below is the complete file, read from the example project.

    Diagram
    # Generated by make: never commit these
    build/
    *.vcd
    *.vvp
    *.log

    This listing is the whole ignore file: the build/ folder, waveform dumps (VCD, which means value change dump: the recorded file of signal changes), compiled simulation binaries, and logs.

    Each line is a pattern, not a single file. build/ ignores the whole folder wherever make created it, and *.vcd ignores every waveform file in any folder. The comment on the first line speaks for all four: these files are generated by make, so committing them would save exhaust alongside the engine.

    The ignore file only protects files that are not saved yet. If a generated file was committed before the rule existed, ignoring it afterwards does not remove the saved copy. Check git status --short after your first build: the right column of the figure should stay invisible there.

    Compile order matters, and the Makefile owns it

    One awareness-level warning before you write any hardware. The order in which files are handed to the compiler can matter: definitions must exist before the code that uses them. SystemVerilog packages, which are shared collections of types and constants, come first, then the modules that use them. You do not manage this by hand: the Makefile lists the files on each tool command line in a working order, for example the design file before the testbench on the simulation line.

    Take this as a habit. When you add a file, put it in the folder of its role and add it to the matching Makefile line in the established order. A later lesson on the design loop shows those tool commands running.

    Predict what `make clean` removes

    Predict first You run make clean in the project root. Which files disappear, and what rebuilds them?

    Only the contents of build/ disappear: the compiled simulation, the logs, and any waveforms the tools wrote there. Every source file stays untouched. The next make sim recreates build/ and everything in it from source, which is exactly why the right column of the figure is safe to lose.

    Diagram
    // snippet
    clean:
    	rm -rf $(BUILD)

    This snippet is the clean target at the end of the project Makefile: it removes the build/ folder and nothing else.

    Three layout mistakes and their fixes

    • Saving generated files. You commit build/sim.vvp or a waveform because it felt like progress. Every later change silently disagrees with the saved copy. Fix: delete the file, confirm .gitignore covers its pattern, and commit the deletion so the file leaves history going forward.

    • One folder for everything. The design, the testbench, and last week waveform sit side by side, so no path states any file job. Fix: move each file to the folder of its role using the figure as the map, and update the Makefile lines that name moved files.

    • Two copies of one testbench. tb_mini_controller.sv and tb_mini_controller_old.sv disagree, and nobody knows which one the last green run used. Fix: compare the two, rescue anything the old one knows, keep a single copy in tb/, and let version control remember the rest.

    Rule: source is saved and generated is rebuilt, so each file lives with its role and never with its exhaust.

    A teammate sends you this folder. Sort it: which files stay, which move, and which go? The listing below is illustrative: a made-up messy folder, not the course example. Propose the clean layout before reading the answer.

    Diagram
    # Illustrative messy folder, not the course example
    mini_controller.sv
    tb_mini_controller.sv
    tb_mini_controller_old.sv
    sim.vvp
    wave.vcd
    spec.md
    notes.txt
    Check yourself Answer: what does the clean layout look like, and why?

    Move mini_controller.sv to rtl/ and the newest testbench to tb/ as the single tb_mini_controller.sv. Compare the old copy against it, rescue anything worth keeping, then delete it: version control already remembers it. Move spec.md to docs/. Delete sim.vvp and wave.vcd: they are generated and make rebuilds them. Put notes.txt in docs/ if the team needs it, or delete it.

    Check yourself git status --short shows build/sim.log as a new file after your first simulation. What went wrong, and what is the fix?

    The build/ pattern is missing or misspelled in .gitignore, so version control sees generated output as new source. Fix: restore the build/ line in .gitignore, delete nothing by hand beyond that, and confirm the next git status --short no longer lists anything under build/.

    Interview

    Asked: "How do you organise an RTL project?"

    Weak answer: I keep the design and the testbench in one folder so everything is easy to find.

    Strong answer: One folder per role: rtl for the design, tb for testbenches, model for the golden model, docs for the spec, with a Makefile driving it all. Generated output goes to build/, which .gitignore excludes, so version control holds only source.

    Follow-ups: (1) Which files must never be committed, and how do you enforce that? (2) Where does a new shared package file go, and what must change besides its location?

    Key takeaways

    • Source is written by humans and saved; generated output is rebuilt by tools and ignored, never the reverse.

    • One folder per role makes every path state its job, and the Makefile owns task names and compile order.

    • The .gitignore file lists generated patterns once so every machine ignores the same exhaust.

    Keep going

    Next: Lesson 2.3, Git: Save, Compare, Undo. The layout is clean and the ignore file guards it. Next you save snapshots of it and learn to undo mistakes.

    Related topics

    • Previous lesson: Shell Survival Kit

    • Next lesson: Git: Save, Compare, Undo

    Previous

    11 / 47

    Next: Git: Save, Compare, Undo

    Up next

    Up nextGit: Save, Compare, Undo

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Installing and Checking Tools
    • Reading Tool Messages