|
| 1 | +# Contributing |
| 2 | + |
| 3 | +This is a real-money trading system. The bar is higher than for most codebases, and the |
| 4 | +reasons are in [`CLAUDE.md`](CLAUDE.md) §5 and §6. Read those first. |
| 5 | + |
| 6 | +--- |
| 7 | + |
| 8 | +## Before you write RTL |
| 9 | + |
| 10 | +1. **Read the governing manual.** Every block has one; it is named in the module header. |
| 11 | + The manuals encode the constraints that make the design correct *and* fast. Skipping |
| 12 | + them produces code that synthesizes, misses timing, and blows the latency budget. |
| 13 | +2. **State the latency budget** in nanoseconds and cycles, in the module header. A block |
| 14 | + without a budget is not reviewable. |
| 15 | +3. **State the resource budget** — LUT/FF/BRAM/URAM/DSP — in the same header. |
| 16 | + |
| 17 | +## Coding standard |
| 18 | + |
| 19 | +Full detail in [`manuals/00-foundations/03-hdl-and-rtl-coding.md`](manuals/00-foundations/03-hdl-and-rtl-coding.md). |
| 20 | + |
| 21 | +- Synthesizable **SystemVerilog IEEE 1800-2017**. `logic` only, never `reg`/`wire`. |
| 22 | +- `always_ff` / `always_comb` only. Never bare `always`. `<=` in ff, `=` in comb. |
| 23 | +- **No latches.** Default assignments open every `always_comb`; every `case` has a `default`. |
| 24 | +- Synchronous active-high `rst`. Reset control state only, never datapath registers. |
| 25 | +- Registered outputs by default; exceptions justified in a comment. |
| 26 | +- All literals sized (`8'd5`), all parameters typed (`parameter int unsigned`). |
| 27 | +- Named generate blocks. One module per file, filename == module name. |
| 28 | +- `` `default_nettype none `` at the top, `` `default_nettype wire `` at the bottom. |
| 29 | +- SVA assertions inside `` `ifndef SYNTHESIS `` on every stream interface and invariant. |
| 30 | +- **No division, no modulo, no floating point.** |
| 31 | + |
| 32 | +CDC uses only the sanctioned primitives in [`rtl/common/`](rtl/common/). Hand-rolling a |
| 33 | +synchronizer is a review failure, not a style disagreement — the failure mode is a design |
| 34 | +that works for months and then corrupts one order. |
| 35 | + |
| 36 | +## Before you open a PR |
| 37 | + |
| 38 | +```bash |
| 39 | +python3 scripts/validate.py --ignore-category broken-link # must exit 0 |
| 40 | +./scripts/lint.sh # Verilator, -Wall clean |
| 41 | +make -C scripts sim # testbenches pass |
| 42 | +``` |
| 43 | + |
| 44 | +- **Every fast-path module needs a testbench.** No exceptions. |
| 45 | +- Do not report "done" until place-and-route timing closes. |
| 46 | +- Quote **WNS/TNS and utilization verbatim from the report**. Never estimate them. |
| 47 | +- If a latency number was simulated, say "simulated". If measured on hardware, say |
| 48 | + "measured, N=…". These are not interchangeable and conflating them wastes everyone's time. |
| 49 | + |
| 50 | +## Suppressing a validator rule |
| 51 | + |
| 52 | +Rules can be suppressed, but never silently: |
| 53 | + |
| 54 | +```systemverilog |
| 55 | +localparam real CLKFB_MULT_F = 12.500; // validate: allow real — vendor MMCM declares it real |
| 56 | +``` |
| 57 | + |
| 58 | +The justification is mandatory. A suppression without one is itself reported. |
| 59 | + |
| 60 | +--- |
| 61 | + |
| 62 | +## 🔒 Changes that need extra care |
| 63 | + |
| 64 | +These have a blast radius beyond the file you are editing. |
| 65 | + |
| 66 | +| Change | Requirement | |
| 67 | +|---|---| |
| 68 | +| **Risk limits, order sizing, kill switch** | Separate commit, separate review, separate audit entry. **Never bundled with other work.** | |
| 69 | +| **`rtl/pkg/trading_pkg.sv`** | System-wide contract. Say so explicitly and update the latency budget in the same commit. | |
| 70 | +| **`rtl/fpga_top.sv`** | Holds the master latency budget. Any added cycle must be justified in the PR. | |
| 71 | +| **ITCH/OUCH field offsets** | Must be verified against the current spec PDF and the verification recorded. A wrong offset produces a decoder that corrupts *some* messages silently. | |
| 72 | +| **Anything touching a live venue** | Never. Simulated and UAT endpoints only, until conformance certification is complete. | |
| 73 | + |
| 74 | +## What must never be optimized away |
| 75 | + |
| 76 | +The risk gate, the kill switch, gap detection, and the error counters. Removing a check to |
| 77 | +save a cycle converts a latency problem into a solvency problem. |
| 78 | + |
| 79 | +## Never commit |
| 80 | + |
| 81 | +Venue credentials, comp IDs, session IDs, MPIDs, production IP addresses, or recorded |
| 82 | +exchange market data. `.gitignore` covers the common cases; it is not a substitute for |
| 83 | +looking at your diff. |
| 84 | + |
| 85 | +--- |
| 86 | + |
| 87 | +## Commit messages |
| 88 | + |
| 89 | +Conventional-Commit prefixes (`feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`, |
| 90 | +`build:`), imperative mood, subject ≤ 72 chars. The body explains **why**, not a file-by-file |
| 91 | +recap — and in this codebase the *why* is usually a failure mode being prevented. Say what |
| 92 | +it is. |
0 commit comments