可惜的位選和部分選擇功能Verilog是表達式操作數的一部分。它們不是Verilog運算符(參見Verilog 2005標準文檔的第5.2.1節,IEEE標準1364-2005),因此不能應用於任何表達式,而只能直接應用於寄存器或連線。
有多種方法可以做到你想要什麼,但我會建議使用一個臨時的64位變量:
wire [31:0] A, B;
reg [63:0] tmp;
reg [31:0] ab_lsb, ab_msb;
always @(posedge clk) begin
tmp = A*B;
ab_lsb <= tmp[31:0];
ab_msb <= tmp[63:32];
end
(該分配到ab_lsb和ab_msb可能是有條件的,否則一個簡單的「{ab_msb,ab_lsb } < = A * B;「當然也會這樣做的。」)
請注意,我使用阻塞賦值來分配'tmp',因爲我需要下面兩行中的值。這也意味着從外部 訪問'tmp'是不安全的。
另請注意,這裏不需要連接hack {A * B},因爲A * B被分配給64位寄存器。這也符合IEEE標準2064至05年的5.4.1節推薦:
乘法可以不受寬足以容納它分配結果 的東西丟失任何溢出位進行。
但是,您說:「這裏的重點是我無法訪問64位寄存器」。
所以我將介紹一個不使用任何Verilog 64位寄存器的解決方案。然而,這不會對所產生的硬件產生任何影響。 Verilog代碼只會在 中看起來不同。
這個想法是通過移位A * B的結果來訪問MSB位。這樣做的以下幼稚版本將不起作用:
ab_msb <= (A*B) >> 32; // Don't do this -- it won't work!
爲什麼這不起作用的原因是,A * B的寬度由分配,這是32個比特的左手側確定。因此A * B的結果只包含結果的低32位。使得操作自確定的比特寬度的
的一種方式是通過使用連接操作符:
ab_msb <= {A*B} >> 32; // Don't do this -- it still won't work!
現在被使用max確定的乘法的結果的寬度。其操作數的寬度。不幸的是,兩個操作數都是32位,因此我們仍然有32位乘法。所以我們需要擴展一個操作數爲64位,例如通過追加零 (我假設無符號操作數):
ab_msb <= {{32'd0, A}*B} >> 32;
訪問LSB位是容易的,因爲這是反正默認行爲:
ab_lsb <= A*B;
因此,我們最終以下替換代碼:
wire [31:0] A, B;
reg [31:0] ab_lsb, ab_msb;
always @(posedge clk) begin
ab_lsb <= A*B;
ab_msb <= {{32'd0, A}*B} >> 32;
end
Xilinx XST 14.2爲兩個版本生成相同的RTL網表。我強烈推薦第一個版本,因爲它更易於閱讀和理解。如果僅使用'ab_lsb'或'ab_msb',則綜合工具將自動丟棄'tmp'的未使用位。所以沒有什麼區別。
如果這不是您尋找的信息,那麼您可能應該澄清爲什麼以及如何「無法訪問64位寄存器」。畢竟,您也嘗試訪問代碼中64位值的位[63:32]。由於您無法計算產品A * B的高32位而沒有執行低32位所需的幾乎所有計算,您可能會要求一些不可能的事情。
它不混合非阻塞和阻塞任務是問題。 AIUI的問題來自於使用阻塞分配來在不同的硬件塊之間進行通信。 http://www.sigasi.com/content/verilogs-major-flaw – 2013-05-10 11:04:00
@MartinThompson我曾看過,但沒有完整閱讀。我所拿走的所有東西都是'對於同步設計,這使它們無害',但我從來沒有在Verilog中遇到過這個問題,儘管VHDL用戶有時確實指出這個錯誤在VHDL中絕不會發生;) – Morgan 2013-05-10 11:58:15
從我的關鍵位(坦率地說,非Verilogger)的觀點是,你必須從不*使用*阻塞*賦值*通信*。其他任何東西都很好......而且VHDL通過不允許在進程之外訪問變量(具有阻塞語義)來強制執行。 – 2013-05-10 12:12:19