FPGA 不一定要一瞬間算出答案。這篇用國小學過的直式除法,說明兩個「每個時脈算出答案一個位元」的硬體電路:div_seq 和 sqrt_seq。
An FPGA doesn't have to produce an answer all at once. Using the long division you learned in primary school, this page explains two circuits that compute one bit of the answer per clock cycle: div_seq and sqrt_seq.
回想十進位的直式除法,算 157 ÷ 12:
Recall decimal long division, for 157 ÷ 12:
15:12 放得進去 1 次,商寫 1,餘 3。Look at 15: 12 goes in once. Write 1, remainder 3.7 拉下來,變成 37:12 放得進去 3 次,商寫 3,餘 1。Bring down 7 to make 37: 12 goes in 3 times. Write 3, remainder 1.每一步做的事都一樣:拉下一位 → 試試看放不放得進去 → 決定這一位答案 → 更新餘數。
Every step is the same: bring down a digit → see whether the divisor fits → decide this digit → update the remainder.
換成二進位更簡單,因為每一位答案只可能是 0 或 1。只要比大小,夠減就填 1 並減掉,不夠就填 0。硬體只需要一個比較器和一個減法器,每個時脈重複用一次。
Binary is even simpler, because each answer bit can only be 0 or 1. Just compare: if it fits, write 1 and subtract; if not, write 0. The hardware needs one comparator and one subtractor, reused once per clock.
算 quotient = dividend ÷ divisor。有三個參數:
It computes quotient = dividend ÷ divisor, with three parameters:
| 參數Parameter | 意思Meaning | 例子Example |
|---|---|---|
| WN | 被除數 dividend 有幾個位元Width of the dividend | 88 |
| WD | 除數 divisor 有幾個位元Width of the divisor | 44 |
| WQ | 商 quotient 有幾個位元,也是要算幾個時脈Width of the quotient, which is also the number of clocks | 36 |
| 名稱Name | 意思Meaning | 對應直式除法的In long division |
|---|---|---|
| d | 除數,算的過程中不變The divisor, fixed during the run | 除數The divisor |
| rem | 目前的餘數The current remainder | 每一步減完剩下的數What's left after each subtraction |
| lo | 被除數還沒拉下來的位元Dividend bits not yet brought down | 還沒用到的位數Digits not used yet |
| q | 目前算到一半的商The partial quotient | 商寫到一半The answer written so far |
| cnt | 還剩幾步Steps left | — |
| busy / done | 正在算 / 算完了(只亮一個時脈)Working / finished (high for one clock) | — |
wire [WD:0] rem_next = {rem[WD-1:0], lo[WQ-1]}; // rem × 2 + next bit 餘數 × 2 + 拉下的那一位 wire fits = (rem_next >= {1'b0, d}); // fits → this bit is 1 夠減 → 這位商是 1
{A, B} 是把位元接起來。把餘數左移一位再補上新的一位,等於「乘 2 再加上新位」,就像十進位的「3 拉下 7 變成 37」是 3 × 10 + 7。
{A, B} joins bits together. Shifting the remainder left by one and appending the new bit means "times 2, plus the new bit", just as bringing down 7 after 3 gives 37 = 3 × 10 + 7 in decimal.
rem 是 [WD:0],比除數多留一格。The remainder is below d. Doubled plus one, it can reach 2d − 1, which may need one more bit than d. So rem is [WD:0], one bit wider than the divisor.lo <= lo << 1; // next bit to the front 下一位移到最前面 rem <= fits ? rem_next - {1'b0, d} : rem_next; // subtract if it fits 夠減就減 q <= {q[WQ-2:0], fits}; // shift in the new bit 商左移,新位補在右邊 cnt <= cnt - 1'b1;
最後一步要寫 quotient <= {q[WQ-2:0], fits} 而不是 quotient <= q。因為 <= 是非阻塞賦值,同一個時脈裡 q 還是舊的值,要自己把最後一位接上。
On the last step the code writes quotient <= {q[WQ-2:0], fits}, not quotient <= q. <= is a non-blocking assignment, so within the same clock q still holds its old value, and the last bit has to be appended by hand.
縮小成 WN = 5、WD = 2、WQ = 3。13 = 01101,上面 2 位 01 當初始餘數,下面 3 位 101 放進 lo。除數 3 = 11。
Scale down to WN = 5, WD = 2, WQ = 3. 13 = 01101: the top 2 bits 01 are the initial remainder and the low 3 bits 101 go into lo. The divisor 3 = 11.
| 步驟Step | 拉下Bit in | rem_next | ≥ 3?≥ 3? | 新 remnew rem | q |
|---|---|---|---|---|---|
| 1 | 1 | 1×2+1 = 3 | 是 → 1yes → 1 | 0 | 1 |
| 2 | 0 | 0×2+0 = 0 | 否 → 0no → 0 | 0 | 10 |
| 3 | 1 | 0×2+1 = 1 | 否 → 0no → 0 | 1 | 100 |
商 = 100 = 4,餘 1。驗算:3 × 4 + 1 = 13。
Quotient = 100 = 4, remainder 1. Check: 3 × 4 + 1 = 13.
start : ‾\____________________________ ← one pulse 給一下 start busy : __/‾‾‾‾‾‾‾ WQ clocks ‾‾‾‾‾\_____ done : _________________________/‾\___ ← one clock; quotient valid 只亮 1 個時脈
開始計算時,電路把被除數切成兩段:
At the start, the circuit splits the dividend in two:
rem <= dividend[WN-1:WQ]; // upper part → starting remainder 上半部 → 一開始的餘數 lo <= dividend[WQ-1:0]; // lower WQ bits → brought down one by one 下半部 → 一位一位拉下來
為什麼可以這樣?回到 157 ÷ 12。第一步看 1,12 放不進去,商是 0、餘數是 1,這步等於白做。所以可以直接把 1 當成起始餘數,從「拉下 5」開始,只要兩步就得到兩位數的商 13。
Why does that work? Back to 157 ÷ 12. The first step looks at 1: 12 doesn't fit, so the digit is 0 and the remainder is 1. That step does nothing useful. So we can start with 1 as the remainder, begin at "bring down 5", and get the two-digit quotient 13 in two steps.
只要上半部小於除數,那些位置的商一定全是 0,可以整段跳過。這讓 88 位元的被除數只需要 36 步,而不是 88 步。
As long as the upper part is smaller than the divisor, every quotient bit in that range is 0 and the whole range can be skipped. That is how an 88-bit dividend needs only 36 steps instead of 88.
1257 ÷ 12,上半部 12 不小於 12,真正的商 104 有三位,但電路只算兩位,結果就會錯。而且電路不會報錯,只會默默給錯的數字。The upper part must be smaller than the divisor. In 1257 ÷ 12 the upper part 12 is not smaller than 12. The real quotient 104 has three digits but the circuit only produces two, so the result is wrong. The circuit does not report an error; it quietly outputs the wrong number.WN、WD、WQ 都是 parameter,在合成時就固定了。Quartus 會照這個數字做出那麼多個正反器,電路做好之後就像蓋好的房子,房間數量不能再改。所以設計者必須在寫程式時就用紙筆分析好。
WN, WD and WQ are parameters, fixed at synthesis. Quartus builds exactly that many flip-flops. Once built, the circuit is like a finished house: you can't add rooms. So the designer has to work the widths out on paper before writing the code.
FPGA 常用整數表示小數,約定「最後 f 個位元是小數」。例如 Q2.34 是 2 位整數加 34 位小數,共 36 位元,數值 = 整數值 ÷ 234。相除時:
FPGAs often store fractions as integers, agreeing that "the last f bits are the fraction". Q2.34 means 2 integer bits plus 34 fraction bits, 36 bits in all, with value = integer ÷ 234. When dividing:
要算 z × |Tx| ÷ |Tz|:
We need z × |Tx| ÷ |Tz|:
| 項目Item | 格式Format | 位元Bits |
|---|---|---|
| z | Q4.24 | 28 |
| |Tx| | Q2.30 | 32 |
| 被除數 z × |Tx|(相乘位數相加)Dividend z × |Tx| (widths add when multiplying) | Q6.54 | WN = 60 |
| 除數 |Tz|Divisor |Tz| | Q2.30 | WD = 32 |
| 商:小數 54 − 30 = 24 位,整數見下Quotient: 54 − 30 = 24 fraction bits; integer bits below | Q5.24 | WQ = 29 |
整數要幾位?這個題目裡 z 最大 6、|Tx| 最大 1、|Tz| 最小 1/3,所以答案最大 6 × 1 ÷ (1/3) = 18。18 < 25 = 32,整數 5 位就夠。
How many integer bits? Here z is at most 6, |Tx| at most 1 and |Tz| at least 1/3, so the answer is at most 6 × 1 ÷ (1/3) = 18. Since 18 < 25 = 32, 5 integer bits are enough.
紙筆推導可能漏掉情況,所以最後還要用模擬把所有可能的輸入跑一遍,和電腦的浮點數答案比對。誤差特別大的地方,通常就是某個寬度估錯、溢位了。
Paper analysis can miss cases, so the last step is to simulate every possible input and compare against a floating-point answer. Where the error is unusually large, some width was usually too small and overflowed.
算 root = ⌊√radicand⌋(無條件捨去)。輸入 W 位元,輸出 N = W/2 位元。
It computes root = ⌊√radicand⌋ (rounded down). The input has W bits and the output N = W/2 bits.
localparam N = W / 2;
N 同時代表三件事:答案有幾個位元、被開方數分成幾組(每組 2 位)、要算幾個時脈。例如 W = 88 時 N = 44。N 用 localparam 是因為它由 W 算出來,外面不能改,避免兩個數被設成互相矛盾。
N means three things at once: the number of answer bits, the number of 2-bit groups in the radicand, and the number of clocks. With W = 88, N = 44. N is a localparam because it is derived from W and can't be overridden, so the two can never disagree.
答案多一位,平方就多兩位。3² = 9(1 位)、30² = 900(3 位)、300² = 90000(5 位)。所以被開方數要兩位兩位一組,每組決定答案的一位。
One more digit in the answer means two more digits in its square: 3² = 9 (1 digit), 30² = 900 (3 digits), 300² = 90000 (5 digits). So the radicand is taken in pairs, and each pair decides one answer bit.
目前的答案是 q,下一位可以填 0 或 1:
The answer so far is q. The next bit can be 0 or 1:
2q(左移一位 = 乘 2)Append 0: the new answer is 2q (shift left = times 2)2q + 1Append 1: the new answer is 2q + 1兩者的平方差多少?用乘法公式 (a + b)² = a² + 2ab + b²:
How far apart are their squares? Using (a + b)² = a² + 2ab + b²:
(2q + 1)² − (2q)² = 4q² + 4q + 1 − 4q² = 4q + 1
所以「這一位能不能填 1」就是「剩下的餘數夠不夠再減掉 4q + 1」。而 4q + 1 在二進位裡就是 q 後面接上 01,不需要乘法器:
So "can this bit be 1?" is the same as "is the remainder at least 4q + 1?". In binary, 4q + 1 is just q followed by 01, so no multiplier is needed:
wire [N+1:0] rem_next = {rem[N-1:0], x[W-1:W-2]}; // rem × 4 + next two bits 餘數 × 4 + 拉下的兩位 wire [N+1:0] trial = {q, 2'b01}; // 4q + 1 wire fits = (rem_next >= trial);
餘數為什麼乘 4?因為答案變成 2 倍,平方就變 4 倍,舊餘數也要跟著放大 4 倍。左移兩位就是乘 4。
Why multiply the remainder by 4? Doubling the answer quadruples its square, so the old remainder scales by 4 too. Shifting left by two is multiplying by 4.
W = 6、N = 3。45 = 101101,分成 10 | 11 | 01,餘數從 0 開始。
W = 6, N = 3. 45 = 101101, split into 10 | 11 | 01. The remainder starts at 0.
| 步驟Step | 拉下Bits in | rem_next | 4q+1 | 夠減?Fits? | 新 remnew rem | q |
|---|---|---|---|---|---|---|
| 1 | 10 | 0×4+2 = 2 | 1 | 是 → 1yes → 1 | 1 | 1 |
| 2 | 11 | 1×4+3 = 7 | 5 | 是 → 1yes → 1 | 2 | 11 |
| 3 | 01 | 2×4+1 = 9 | 13 | 否 → 0no → 0 | 9 | 110 |
root = 110 = 6,餘 9。驗算:6² + 9 = 45。
root = 110 = 6, remainder 9. Check: 6² + 9 = 45.
在光線折射的計算裡,要把法向量變成長度為 1 的單位向量:
In the light-refraction calculation, the surface normal has to be scaled to a unit vector of length 1:
開根號時小數位數也減半:84 位小數 → 42 位小數。三個除法器同時把 x、y、z 分量除以長度。單位向量的分量一定在 −1 到 1 之間,所以 Q2.34 的 2 位整數就夠,初始餘數的條件也一定成立。
A square root also halves the fraction bits: 84 → 42. Three dividers divide the x, y and z components by the length at the same time. Unit-vector components always lie between −1 and 1, so the 2 integer bits of Q2.34 are enough and the initial-remainder condition always holds.
輸入數字,看電路每一個時脈在做什麼。這裡用 JavaScript 照著 Verilog 的步驟模擬。
Enter numbers and watch what the circuit does on every clock. This is a JavaScript model that follows the Verilog step by step.