The two blocks share only a short, explicit signal list. Writing it first catches most integration bugs before any RTL exists.
Signal | Direction | Meaning | When valid |
|---|---|---|---|
| controller → datapath | Load | IDLE && start at an acceptance edge; reset inactive |
| controller → datapath |
| Only when |
| controller → datapath |
| Only when |
| datapath → controller | Status: | Continuously driven; meaningful for the current operation in RUN after load |
| datapath → controller | Status: | Same RUN-phase validity; operands are unreset and may be X before load |
| outside ↔ controller | Command offer and completion | Accept start only in IDLE; done high for the DONE cycle |
| datapath → outside | Completed GCD | Valid with done and held until the next accepted load, unless reset cancels validity |
With reset inactive, acceptance is state == IDLE && start at a rising edge; operands must be positive and meet setup/hold there. Offers in RUN or DONE are ignored, with no queue. A pulse confined to DONE is lost; a held start is accepted at a later IDLE edge and can launch another transaction. Reset cancels outstanding work and invalidates the result; this datapath deliberately does not reset its operand registers.
Controls are decoded from state (and status), flags come from registers. Neither side reads the other's internal registers.
One cycle, one meaning. Control signals are valid for exactly the cycle in which they are asserted; the datapath acts at the next edge.
Mutually exclusive controls (sub_a and sub_b) are never asserted together; the datapath gives them a defined priority anyway.
Status flags are combinational from registers, so they describe the current values. The controller reacts in the same cycle.
No hidden timing: if the datapath needs two cycles for something, add a status signal (ready) instead of assuming.
The status flags can feed the controller combinationally, which makes the controller's outputs depend on datapath values within the same cycle. That is fine for a single block, and it is the reason the datapath comparators sit on the controller's critical path.
sub_a and sub_b never be asserted together?Both would try to change the operands at the same edge, and in the datapath one has priority over the other, so the result would silently ignore a command. Define mutually exclusive controls and assert only one.