RTL 實作 One-Hot to Binary Converter === 這篇我們要講解用 RTL 實作一個轉換器將 one-hot code 轉成 binary number。 ## Definition 首先先定義這個轉換器的 interface,主要就是輸入一個 `ONEHOT_WIDTH` 長度的 one-hot code `onehot_i` (onehot_i 一定會有一個 bit 是 1) 然後輸出轉換後的 binary number `binary_o`,它的 bit 數為 `BIN_WIDTH`。 ```verilog= module onehot2bin_v1 #( parameter ONEHOT_WIDTH = 16, parameter BIN_WIDTH = ONEHOT_WIDTH == 1 ? 1 : $clog2(ONEHOT_WIDTH) )( input [ONEHOT_WIDTH-1 : 0] onehot_i, output reg [BIN_WIDTH-1 : 0] binary_o ); endmodule ``` ## Design 1 第一種設計很直覺,其實就像下面的邏輯電路,我們只需要一個 MUX 它的輸入是 0 到 `ONEHOT_WIDTH-1` 然後我們就看 onehot_i 的第幾個 bit 是 1 就選擇對應的數字輸出給 binary_o 就行了。  因為我們想要將這個轉換器能夠處理的 one-hot code 的長度參數化 (`ONEHOT_WIDTH`),所以 RTL 的做法是用一個 for loop 來選擇要給 `binary_o` 的值,程式碼如下: ```verilog= module onehot2bin_v1 #( parameter ONEHOT_WIDTH = 16, parameter BIN_WIDTH = ONEHOT_WIDTH == 1 ? 1 : $clog2(ONEHOT_WIDTH) )( input [ONEHOT_WIDTH-1 : 0] onehot_i, output reg [BIN_WIDTH-1 : 0] binary_o ); integer i; always @(*) begin binary_o = 0; for (i=0; i<ONEHOT_WIDTH; i=i+1) begin if (onehot_i[i]) binary_o = i; end end endmodule ``` ## Design 2 第二種設計我是從 [pulp-platform](https://github.com/pulp-platform) 裡的 [common_cells](https://github.com/pulp-platform/common_cells) 這個 repo 看到的,這個設計只用到邏輯閘 AND 跟 OR。 這個設計的思維是,我要知道要輸出的 binary num 的每一個 bit 是 0 或 1。那要如何知道呢? 我們用 one-hot code 長度為 8 來舉例。 One-Hot code 長度為 8 代表輸出的 binary num 可能為 0 到 7,下面我們列出每個值的十進制跟二進制對照表 ``` 十進制 二進制 0 -> 000 1 -> 001 2 -> 010 3 -> 011 4 -> 100 5 -> 101 6 -> 110 7 -> 111 ``` 若要知道每個 binary num 的每個 bit 是 0 或 1,我們需要對每個上面列的把每個十進制值對應的二進制的每個 bit 做成 `mask` 然後跟 `one_hot_i` 做 bit-wise AND,每個 bit 的 `mask` 如下面所示: ``` bit-2 mask = 11110000 bit-1 mask = 11001100 bit-0 mask = 10101010 bit-2 mask bit-1 mask bit-0 mask 0 -> 0 | 0 | 0 1 -> 0 | 0 | 1 2 -> 0 | 1 | 0 3 -> 0 | 1 | 1 4 -> 1 | 0 | 0 5 -> 1 | 0 | 1 6 -> 1 | 1 | 0 7 -> 1 | 1 | 1 ``` 為什麼要這麼做呢? 因為我們只需要知道 `onehot_i` 第 i 個 bit 為 1 對應的值的二進制的每個 bit 是 0 或 1。 假設 `onehot_i = 8'b00001000` 也就是 bit-3 為 1 的話,它跟每個 bit 的 `mask` 做 bit-wise AND,我們可以預期會得到下面這種結果 ``` _ bit-3 mask & onehot_i => 0000|0|000 bit-1 mask & onehot_i => 0000|1|000 bit-0 mask & onehot_i => 0000|1|000 ^ onehot_i 對應的 binary num ``` 我們只留下 bit-3 為 1 對應的值的二進制,其他 bit 都是 0。 最後我們把每個 bit-wise AND 的結果做 logic OR 就可以知道對應的 bit 是 0 或 1。 完整的程式碼如下: ```verilog= module onehot2bin_v2 #( parameter ONEHOT_WIDTH = 16, parameter BIN_WIDTH = ONEHOT_WIDTH == 1 ? 1 : $clog2(ONEHOT_WIDTH) )( input [ONEHOT_WIDTH-1 : 0] onehot_i, output reg [BIN_WIDTH-1 : 0] binary_o ); reg [BIN_WIDTH-1 : 0] bin_num; reg [ONEHOT_WIDTH-1 : 0] mask; integer i, j; always @(*) begin for (i=0; i<BIN_WIDTH; i=i+1) begin for (j=0; j<ONEHOT_WIDTH; j=j+1) begin bin_num = j; mask[j] = bin_num[i]; // transpose end binary_o[i] = |(mask & onehot_i); end end endmodule ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up