Writing specifications
Writing a good spec
What to put in a request so the first result is close to the one you wanted.
The description you type is the whole input. Everything else is a switch; this is the part that decides whether the module you get back is the module you meant. The good news is that a useful spec is short, and the pattern is always the same.
The shape of a good spec
Four things, in roughly this order. You do not need headings or formatting; a paragraph that covers them is enough.
- 1
What the block is
One line. A synchronous FIFO, a UART transmitter, a round-robin arbiter for four requesters.
- 2
Its interface
Ports, widths, and which of them are parameters. If you do not say, reasonable defaults are chosen and you will spend a follow-up correcting them.
- 3
Its behaviour, in the cases that matter
Reset behaviour, what happens at the boundaries (empty, full, overflow, an illegal request), and the timing relationship you expect between inputs and outputs.
- 4
Any constraint you would reject the design over
Registered outputs, no latches, a single clock domain, a specific FSM encoding, meeting a particular frequency. Say it here rather than discovering it in review.
Be specific about timing and reset
These two produce more rework than everything else combined, because both have several defensible answers and the model has to pick one.
- Reset. Synchronous or asynchronous, active high or active low. If your project has a house style, set it once in Coding style and stop repeating it.
- Latency. Say whether an output appears in the same cycle as its input or the cycle after. "Registered output" is a complete answer.
- Handshakes. If you mean ready/valid, say ready/valid, and say whether ready may depend combinationally on valid.
From vague to usable
Here is the same request written three ways, and what each one gets you.
Too vague
Make me a FIFO.You will get a FIFO. Its width, depth, reset style, full and empty semantics and whether it registers its outputs are all guesses. Most of them will be fine and one of them will not, and you will find out during review.
Good enough
Synchronous FIFO, 32 bits wide, 16 entries deep, single clock.
Full and empty flags. Synchronous active-low reset.This is the level most people should aim for. The interface is pinned down and the remaining choices are ones you probably do not care about.
Precise
Synchronous FIFO with a single clock.
Parameters: DATA_WIDTH (default 32), DEPTH (default 16, power of two).
Ports: clk, rst_n, wr_en, wr_data, rd_en, rd_data, full, empty, count.
Behaviour:
- Synchronous active-low reset clears the pointers, count, and flags.
- A write when full is ignored and does not corrupt the contents.
- A read when empty returns the last valid data and does not move the pointer.
- Simultaneous read and write when neither full nor empty is allowed.
- rd_data is registered; it appears the cycle after rd_en.
- count is the number of valid entries, 0 through DEPTH.
Constraints: no latches, all outputs registered, one clock domain.Worth writing when the block is going into something you cannot easily change later. It also makes the testbench far more useful, because every line above is something the test plan can turn into an assertion.
Things that do not help
- Asking for several unrelated modules at once. One module per chat. The verification step is built around a single design under test.
- Pasting a whole datasheet. Quote the register map or the timing diagram you actually need; the rest is noise that pushes out the part that matters.
- Style instructions in every message. Put them in Coding style once and they apply to every run.
- Describing the implementation instead of the requirement. "Use a Gray-coded pointer" is fine as a constraint; as the whole spec it leaves the behaviour undefined.
Iterating beats rewriting
If the first result is close but wrong somewhere, say what is wrong in a follow-up rather than rewriting the whole spec. The reset should be asynchronous or full should assert one cycle earlier are complete instructions in context, and they keep everything that was already right.
Tip
When you find yourself explaining the same constraint for the third time in one chat, that is a signal to start a fresh chat with the constraint written into the opening spec.