用 邏輯電路 實現一個 開平方 算法


這篇文章 的 起因 是  《小夢 在 民科吧 發了一個 用 四則運算 開平方 的 帖》  https://www.cnblogs.com/KSongKing/p/13296121.html    。

 

《小夢 在 民科吧 發了一個 用 四則運算 開平方 的 帖》    也 發到了 反相吧  《小夢 在 民科吧 發了一個 用 四則運算 開平方 的 帖》  https://tieba.baidu.com/p/6811112759     。

 

我在 帖 里的  12 樓 說了,  小夢 的 算法 簡單小巧,   適合 用在 計算器 上,   我們可以 設計一個 硬件電路 來 實現 它  。

 

這個 算法 是,   設 b 為 被開方數,   任取一個 正數 a,   令   c  =  ( b - a ² )  /  ( 2 a )  ,   令  a = a + c ,    重復若干次 這個過程,   a 就 很接近 b 的 平方根    了  。

 

這個 算法 可以 稱為  “小夢算法”   。

 

 

先畫 一個 邏輯電路圖 :

 

                                        圖 (1)

 

 

 

左邊 的   a 、b 、c 、diff 、v1 、v2 、abs_diff 、max_diff   是  存儲單元,  也就是 內存,   也就是 內存單元,    假設 每個 存儲單元 是 64 位 的,   可以 存儲  64 位 浮點數  。

 

右邊 的   F1 、F2 、F3 、F4 、F5 、F6   是  控制單元,   具體 的 控制 和 運算 邏輯 就在 控制單元 里 實現  。

 

橙色線 和 橙色箭頭 是  控制信號線路 和 信號傳遞方向,    藍色線 是 數據線路,     一根 線 在 實際中 可能是 多位 的  。

綠色線 和 綠色箭頭 也是 控制信號線路,    表示 和 橙色 不同 的 控制分支 。

 

F1 、F2 、F3 、F4 、F5 、F6    都 會有 數據線 和  相關的 存儲單元 相連,    圖中 用 藍線 簡略 的 表示,  並沒有 畫出 具體 的 連接 線路  。

 

我們 定義 :      有電壓 為 1,  無電壓 為 0     。

 

開始運算 時,    輸入端  輸入 一個  1 脈沖,  就可以 觸發 電路 開始 進行 開平方 運算  。    注意 是  1 脈沖,   不是 持續 的 1  。

 

先介紹一下 存儲單元,   

 

a   存放 a,    a 是 中間結果,  也是 最終結果

b   存放 b,    也就是 被開方數

v1   存放  a ²  

diff   存放   b  -  a ²   

v2    存放   2 * a   

c   存放   diff / v2   

abs_diff   存放  diff 的 絕對值

max_diff   存放 精度值,   當    b  -  a ²   的 絕對值 , 也就是  abs_diff   小於  max_diff  時,  a 為 達到 精度 的 開方結果 ,  可以輸出  。

 

開始 運算 前,     先 把 被開方數  存到  b,    同時 任取一個 正數, 比如 1 ,  存到 a  。

 

然后,   向 輸入端 輸入 一個   1 脈沖,   F1  接收 到  1 脈沖 后 接通電路,  開始工作 。   F1 的 工作 是 發信號 給 運算器,  讓 運算器 計算 a ²,  運算器 計算 結束后,   F1 把 計算結果 存放到  v1 ,   同時 發出 一個  1 脈沖,  觸發  F2  開始工作  。

 

運算器 在  這個 圖 里 沒有 畫出來,    運算器 是 一個 公共部件,     F1 、F2 、F3 、F4 、F5 、F6  都會去調用  。

 

F1  的 內部電路  會 在 下文 畫出來,   里面 會 畫出  F1  調用  運算器 的  電路 和 邏輯  。

 

F1  的 內部電路  如下 :

 

                           圖 (2)

                          圖 (3)

 

 

 

 

 

 

輸入端 接收 到  1 脈沖,   這個 1 脈沖 會讓  “讓 寄存器 A 變成 寫入狀態”   電路 接通,  這個電路 會 向  寄存器 A  發出 信號,   告訴 寄存器 A 變成 寫入狀態,

同時,  輸入端  的  1 脈沖  還會 讓  “讓 寄存器 B 變成 寫入狀態”  電路 接通,  這個電路 會 向 寄存器 B  發出 信號,   告訴 寄存器 B 變成 寫入狀態,

同時,  輸入端  的  1 脈沖  會 觸發   延時開關,    延時開關 在 一段時間 后 輸出 一個  1 脈沖 ,   這個  1 脈沖 會 接通 下一個 操作 的 電路 。

 

這樣 就可以 在 一個 操作 完成后 觸發 下一個 操作 執行  。

 

為什么要用 延時開關 呢 ?    是 為了  確保 上一個 操作 完成 后,  才 觸發 下一個 操作  。   因為  電路 的 運行 需要時間, 每一段電路 運作 需要 的 時間 也 不完全相同,  所以 需要 延時開關 在 一段時間 后 發出 1 脈沖 觸發 下一個 操作,   這段時間 應該 足夠 完成 當前操作,   這樣 來 確保 觸發 下一個 操作時,  當前 操作 已經 完成  。  

 

從 圖上 可以看到,      “讓 寄存器 A 變成 寫入狀態”    和    “讓 寄存器 B 變成 寫入狀態”   是  F1  的  第一個 步驟,  這 2 個 操作 是 同時執行 的,  也可以說是 並行 執行 的  。

 

第 1 個 步驟 有 一個 延時開關,   當   “讓 寄存器 A 變成 寫入狀態”    和    “讓 寄存器 B 變成 寫入狀態”    完成 后,   延時開關 發出 1 脈沖,   觸發 下一個 步驟  。

 

第 2 個 步驟 包含 2 個 操作,    “打開 a 和 寄存器 A 的 通路,  讓 a 的 數據 寫入 寄存器 A”  和  “打開 a 和 寄存器 B 的 通路,  讓 a 的 數據 寫入 寄存器 B”  ,

這 2 個 操作 也是 同時執行 的,    第 2 個 步驟 也 有 一個  延時開關,   這 2 個 操作 完成 后,     延時開關 發出 1 脈沖,   觸發 下一個 步驟  。

 

到 目前為止,   每一個 操作 是 一段 電路,   這一段 電路 在 輸入端 輸入 1 脈沖 時 工作,   1 脈沖 結束 后 電路 停止  。

1 脈沖  是 有電壓,  這個 電壓 使得 電路 接通 並 工作,    1 脈沖 結束 后,   無電壓,   電路不工作 。  延時開關 被 觸發 后,   即使  輸入端 的 1 脈沖 結束,  也會 在 設定好 的 時間 后 在 輸出端  發出  1 脈沖   。

 

當然,  我們需要 知道 每一個 步驟 完成 的 最大時間,  以此 來 設置 這個 步驟 的 延時開關 的 延遲時間,    延遲時間 應該 比 步驟 完成 的 最大時間 更大一點,   這樣 有一點 冗余,    有利於 電路 的 穩定運行  。

 

 

圖 (3)   的 第一個 操作 是  “向 運算器 發出 指令 計算 乘法”,    同時 會 觸發 延時開關,   延時開關 發出  1 脈沖 應該是在 運算器 完成 運算 之后  。

也就是說,  延時開關 的 延遲時間 應該是   “向 運算器 發出 指令 計算 乘法” 電路 的 運行時間  +   運算器 計算乘法 的 時間  +   冗余時間    。

 

這需要 設計者 了解 運算器 的 運算時間 ,    並以此 給 延時開關 設定 延遲時間   。

 

這個 設計 不算太好,     從 軟件設計 的 角度來講,  封裝性 不太好,    高內聚 低耦合 不足 。   因為 這需要 運算器 將 運算時間 告知 其它 元件,  當  運算器 的 運算時間 發生變化,  與之相關 的 操作 的 延時開關  的 延遲時間 都要 修改  。

 

所以,  我們可以 把   圖 (3)    的  這部分 設計 改一下 :

 

 

                          圖 (4)

 

 

 

 

圖 (4)  和  圖 (3) 不同 的 地方 是 “向 運算器 發出 指令 計算 乘法”  的 下面 是  “一次性開關”,    圖 (3) 中 此處 是 延時開關   。

 

運算器 計算 完成 時  會  通過 輸出端  輸出 1 脈沖, 表示 計算完成,  這個 1 脈沖 會 觸發  外部電路  進行 下一步 操作  。

 

實際上 可以 不用 延時開關,  讓 運算器 的 輸出端 直接 連到 到 下一個 操作 的 電路,   運算器 計算完成 時 在 輸出端 輸出  1 脈沖  可以 直接 觸發 下一個 操作 的 電路   。

 

為什么 這里 要用  一次性開關 呢  ?

 

因為   有 多個 元件 會 用到 運算器,   所以,   運算器 的 輸出端 會 連接 到 多個 元件,   向 多個 元件 輸出 完成信號  1 脈沖,  這就需要 區分  當前 調用 運算器 的 是 哪一個 元件,   運算器 輸出 的  完成信號  應該 只 發給 當前 調用 運算器 的 元件  。

 

此時,    一次性開關   就 派上用場  了   。

 

一次性開關  是 這樣 :

 

                         

 

 

開始時,    一次性開關 處於 停止狀態,   輸出端 輸出 0, 也就是 無電壓   。

當 控制端 輸入 1 脈沖 時,  觸發  一次性開關,  進入 工作狀態,    進入 工作狀態 后,   輸出端 仍然 是 0,   當 輸入端 輸入 1 脈沖  時,   輸出端 輸出 1 脈沖,   同時,   停止 一次性開關,    讓 一次性開關 恢復 停止狀態  。

在 停止狀態 下,    無論 輸入端 輸入 1 還是 0,    輸出端 的 輸出 都是 0   。      或者說,  在 停止狀態 下,  輸入端 的 輸入 無效  。

 

 

圖 (1) 里 的  F6  “判斷 abs_diff < max_diff”   會 2 次 用到 運算器,  一次 是 計算  diff 的 絕對值 (diff 的 絕對值 會 存到 abs_diff ),  一次 是 比較  abs_diff 和 max_diff      的 大小   。

 

運算器 除了 加減乘除,  還 可 求 絕對值 和 比較大小,     把 要 求 絕對值 的 數 放到 寄存器 A,   再 發指令 告知 運算器 求 絕對值,  運算器 會 對 寄存器 A 里 的  數   求 絕對值,  並把 結果 存放到 寄存器 C  。

 

運算器  提供 比較 大小 的 功能,   把  要 比較 大小 的 2 個 數 存到 寄存器 A 和 寄存器 B,    發指令 告知 運算器 比較大小,  運算器 會 比較 寄存器 A 和 寄存器 B  里 2 個 數,    運算器 會 提供 3 個 輸出端 來 返回 比較結果,   這 3 個 輸出端 是 “大於” 、“小於” 、“等於” ,   若  A > B ,  大於端 輸出  1 脈沖,  若 A < B, 小於端  輸出  1 脈沖,   若 A = B ,   等於端 輸出  1 脈沖  。

 

 

運算器  本身 是一個 復雜 的 部件,   基本原理 也是 上文 所講 的 邏輯電路 原理 ,   給出 適當 的 算法,  用 上文 的 邏輯電路 原理 可以 設計出 運算器  。

 

到 目前為止,  運算器 提供  加減乘除 、求絕對值 、比較大小,   一共   6 個 功能,  對應 6 個 指令,   可以用 3 位 指令 來 表示  。

 

0 和 1 的 3 位 組合 有 8 種,   000, 001, 010, 011, 100, 101, 110, 111   ,    去掉   000 ,  還有 7 種,   足夠表示 6 個 指令  。

 

為什么 要 去掉 000 呢 ?      因為  000  表示   無指令, 空閑  。

 

6 個 指令 可以這樣 表示  :

 

001       加

010       減

011       乘

100       除

101       求 絕對值

110       比較大小

 

 

運算器 提供 3 位 線路  作為 指令 輸入端 就可以 。     也可以說,   運算器 的 指令 輸入端 是 3 個 引腳  。   也可以說,  運算器 的 指令 輸入端 是 3 條 接線  。

 

 

我以前寫過一篇文章   《漫談 計算機硬件 的 設計 和 實現》   https://www.cnblogs.com/KSongKing/p/9866334.html  ,   介紹過 “指令開關”,  指令開關 的 學名 似乎  叫    “譯碼器” 和 “真值表”   。

 

 

具體 的 電路設計,   比如  上文 涉及到 的 一些 開關元件 :   延時開關  、 一次性開關,   我會 另外寫一篇 文章 《設計 邏輯電路 的 開關元件》 https://www.cnblogs.com/KSongKing/p/13412340.html  來 介紹  。

 

嚴格的說,   上文 說 的  “延時開關” ,    應該是 “延時脈沖開關”,      延時開關 是 觸發 后 延遲一段時間 后 導通,   導通 后 一直 保持 導通狀態  。

 

延時脈沖開關  是  觸發 后 延遲一段時間 后 輸出 一個 脈沖,    脈沖 是 指 導通 一段時間 后 斷開,  並非 一直 導通,   導通時間 就是 脈沖寬度  。

 

當然,  還有 一種 延時開關 是 觸發 后 立即 導通,   延遲一段時間 后 斷開  。 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM