Style Guide - StanfordAHA/aha GitHub Wiki

Style Guide

Version Control

All files and collateral which we want under version control should be checked into a repo. Mainly this includes core source files, scripts, light-weight docs (e.g. .md files), and config files (e.g. .xml files). Big files (e.g. PDF documents, images) should rarely be checked into the repo; Google Drive and Dropbox are much better tools for that.

Commit Messages

We strongly encourage everyone to follow standard commit message protocols. See here for a great primer on commit messages:

  • Separate subject from body with a blank line
  • Limit the subject line to 50 characters
  • Capitalize the subject line
  • Do not end the subject line with a period
  • Use the imperative mood in the subject line
  • Wrap the body at 72 characters
  • Use the body to explain what and why vs. how


The basic workflow is as follows:

  • Create a new feature branch for your work, e.g. refactor-connect-box. Push to this branch -- there should be no restrictions on this.
  • When ready, initiate a pull request (PR)
  • Once someone else has reviewed and accepted your PR, it can be merged into master.

An aside: do your best to avoid a bunch of intermediate merges into master - insteady try rebasing. It makes the commit history much cleaner.

File organization

All top-level modules should go into new directories at the top-level, and should be accompanied by a test directory. For example if you have a module named LineBuffer, create a directory named line_buffer/ (for all source files related to the module) and test_line_buffer/ for all tests related to the module. In general, every new source file should be accompanied with some test (ideally path/to/ contains tests for source in path/to/ Anything that you think can be shared across modules should go in common/ with accompanying tests in test_common/.

Within a module's directory, we expect to have the following files (running with the LineBuffer example):

  • line_buffer/ should contain the functional model for the module.
  • line_buffer/ should contain the magma implementation of the module (if applicable).
  • line_buffer/ should contain the Genesis2 wrapper for the module.
  • line_buffer/genesis/line_buffer.vp should contain the Genesis2 source for the module. All other Genesis2 source needed for this module should also be in this directory (e.g. line_buffer/genesis/sram.vp).
  • test_line_buffer/ should contain tests for the functional model.
  • test_line_buffer/ should contain tests to verify the various implementations against each other, as well as against the functional model.

For each of the files, you can organize/name functions and classes as it most makes sense for the module (keeping to pep8 standards). However, we suggest following the patterns in cb and memory_core. Keeping consistent interfaces and naming conventions will allow for automation and introspection down the road.

Naming conventions

We follow the following naming conventions:

  • All file and directory names should be in snake case, e.g.,, my_dir/sub_dir. No capital letters should appear in file or directory names.
  • Function names should also be in snake case, similar to file names, e.g. def generate_cb().
  • Class names should be in camel case, e.g. class CB, class MyUtilityKlass. Note that for "names" which are acronyms, e.g. FPGA, CGRA, the camel case should keep capitals. E.g. the camel case of "FPGA" is "FPGA".

Python Style

We use the pep8 style guide for Python code. This is the coding convention used for the Python standard library. Note that we use the pycodestyle package for checking (which used to be called pep8 but was renamed).

Our continous integration uses pytest to check pep8 compliance of any code that is checked in. If a code causes a style error, it will cause a build failure.

We suggest using a linting plugin for your editor to help you resolve pep8 issues as you edit rather than after the fact. Here are some options:


Writing generators in magma means writing Python functions that return magma Circuits. Strive to make a clear distinction between the two stages of the computation. In the body of the generator function, you should compute functions of your parameters that might be used in your definition. This is normal Python code. Within the body of the Circuit definition you are generating, you should mainly be writing magma code. It is important to separate Python and magma code as much as possible so your generator is easy to understand.


Prefer using operators versus explicitly instantiating and wiring up modules. Magma overloads operators on the Bit, Bits, UInt, and SInt types, as well as providing a standard set of operators in mantle. Using operators leads to cleaner code that is easier to read and understand.


- config_addr_zero = mantle.EQ(8)
- m.wire(m.uint(0, 8), config_addr_zero.I0)
- m.wire(config_addr_zero.I1, io.config_addr[24:32])
+ config_addr_zero = mantle.eq(m.uint(0, 8), io.config_addr[24:32])
- config_en_set_and_addr_zero = mantle.And(2, 1)
- m.wire(config_en_set_and_addr_zero.I0, io.config_en)
- m.wire(config_en_set_and_addr_zero.I1[0], config_addr_zero.O)
- m.wire(config_en_set_and_addr_zero.O[0], config_cb.CE)
+ m.wire(io.config_en & config_addr_zero, config_cb.CE)


Use function calls when possible

- m.wire(io.config_en & config_addr_zero, config_cb.CE)
- m.wire(config_cb.RESET, io.reset)
- m.wire(config_cb.I, io.config_data)
+ config_cb(io.config_data, reset=io.reset, ce=io.config_en & config_addr_zero)

Wire outputs to inputs

- m.wire(config_cb.RESET, io.reset)
+ m.wire(io.reset, config_cb.RESET)

Minimize name munging

For example, use array types and select based on index instead of generating names with an index embedded (e.g. "in_0", "in_1", ...)

Reuse code

If you see code being repeated across your generators, factor them into helper functions, modules, and packages.

Keep your functions short

Decompose your logic into helper functions so your code is more organized, concise, readable, and maintainable.

Document your code

Include docstrings (see for more info) for any functions. Use inline comments where appropriate.

Include a README with setup instructions and how to use. At a baseline, refer users to your travis script and tests for examples.

Branching and Pull Requests

Code should be developed on a non-master branch, and pull requested into master when ready. All requests require at least on review by a non-author. Keep pull requests as minimal as possible. Organize branches by features and bug fixes.


Our repositories use the pytest framework. To install, run pip install pytest.

We suggest consulting the pytest documentation for full documentation including installation, tutorials, and PDF documents. Here we will cover the basic way pytest is used specifically for our repositories.


The standard pattern for writing pytest tests is to use the Python assert statement. See this page of the pytest documentation for examples and information on using the assert statement with pytest.

Test Discovery

pytest uses a standard test discovery scheme to make it easy to add new tests. Instead of having to do any extra work like adding a test to a configuration file containing a list of tests, all you have to do is name your test in a certain way and place it in the right directory for pytest to automatically discover it. See this page from the pytest documentation for the test discovery scheme.

Basically, files that have the naming scheme test_*.py or * will be considered tests. Within those files, functions with the prefix test_ or functions/methods with the prefix test_ inside a class defined with the prefix Test will be considered tests.


fault is a Python package (part of the magma ecosystem) with abstractions for testing hardware. See the README for example usage and links to documentation.

⚠️ ** Fallback** ⚠️