2012-05-25 50 views
5

有一天,我在Verilog學到了一個很酷的技巧。當你需要反覆做某件事時。您可以使用移位寄存器來計算增量的數量。只需將1從LSB移到MSB,並在到達MSB時完成。硬件啓發循環。廢話?

在C這將是這樣的:

for(j=0b1; !(j & (1<<16)); j=j<<1) 
{ 
/*do a thing 16 times*/ 
} 

我知道它的使用已受到限制,因爲位寬的,但它不涉及任何此外所以它是快。 所以我的問題:有沒有使用這個?在C語言或其他高級語言中使用它是否值得?

也許在資源有限的嵌入式系統中。

感謝

+5

是什麼讓你認爲除了是不是轉移慢?它當然不在任何現代的CPU上,甚至不是嵌入式核心。也不是測試。所以是的,廢話。 –

+0

有趣,但我沒有看到太多的CPU週期收益在這裏。 ! –

+0

@HansPassant我認爲加法器機制比重新安排一些電線需要更多的資源。當我在FPGA上使用這種技術時,我獲得了一些空間。但後來我用了2048位寬的寄存器。 – Stiggo

回答

1

它不涉及任何此外所以它是快速

爲CPU架構轉移快於除?另外,如果結果表明轉換速度更快,您認爲編譯器針對該特定體系結構的做法是否會自動進行優化?

有什麼用呢?

爲了優化目的,沒有也沒有任何使用它。

用於其他目的,是的,這樣的代碼通常用於屏蔽掉一個字節的各個位。我相信,這兩個最常用的方法是這些:

uint8_t mask; 

for(mask = 0x01; mask != 0x00; mask<<=1) 
{ 
    do_something (data & mask); 
} 

for(i=0; i<8; i++) 
{ 
    do_something (data & (1<<i)); 
} 
+0

唯一讓我認爲這種轉換比添加更有效的方式是Verilog,默認情況下+調用32位加法器,而<<僅僅是對電線的重新排序。所以這段代碼可以用來一點一點地遍歷微控制器的PORT?讀一個別針,然後轉到下一個。 – Stiggo

+0

@Stiggo是的,一個端口,一個標誌寄存器,一個數據協議的一部分,一些eeprom設置變量等等。 – Lundin

8

這是非常不值得它。它使代碼更簡潔,更難以閱讀,性能差異可以忽略不計。

您的編譯器可以比您更好地進行這些類型的優化。由於性能原因,這樣的短循環甚至可能會被展開。但是,如果你編寫這樣的循環,編譯器可能無法很容易地弄清楚,所以你甚至可能會放慢程序運行速度。

這實際上是一個微優化的例子,它幾乎肯定不會在程序運行時產生明顯的差異。

1

在一個真實的CPU中,加法是你能做的最快的事情之一;移位是不是任何更快。而且你會讓編譯器更難以高效地進行優化。

+1

也很難閱讀和理解,這是真正的問題。 – Oleksi

1

更快?你確定嗎?至少在MIPS架構上,移位需要和加法一樣長。如果對於最常見的面向消費者的處理器體系結構也是如此,我會感到驚訝。

此外,正如Oleksi指出的,這很難閱讀。可能不值得一個不速的增益。

0

一般來說,如果你想一直循環特定的次數> 0,並儘量減少循環的開銷,那麼我認爲這將是「最好的」:

unsigned i = 16; 

do { 
// do something here 
} while (--i); 



You might get the same result with: 

unsigned i = 0x8000; 

do { 
// do something here 
} while (i>>=1); 

在這一點上,你將不得不看在大會上。

+0

第一個版本更快的原因是,許多體系結構都有一個用於減量的指令,如果不是零則爲分支。 –

5

在我看來,大多數傢伙評論/回答並不真正瞭解提問者在說什麼。 Verilog語言用於硬件設計,硬件設計與軟件設計完全不同,沒有CPU週期或類似的東西。但是,簡短的回答仍然是:沒有。很長的回答:

肯定移位比添加更簡單。對於移位,從FF(觸發器)到FF的邏輯要少得多。另外,進位必須從LSB位傳播到MSB位,這意味着log2(N)級邏輯(N是計數器將達到的最高值)。另一方面,移位寄存器使用N個FF,而加法器只使用log2(N)個FF。 所以有一個性能/區域的權衡也很大程度上取決於N.關於加法一些「獨立」的信息: http://en.wikipedia.org/wiki/Adder_%28electronics%29 找不到換擋類似的文章,但一旦你理解加法器,轉換器應該是顯而易見的。

當您在RTL中設計狀態機時,這可能很重要。但是你提供的代碼實際上與上述無關。 Verilog中的'for'循環意味着所有'工作'將在單個循環中完成。所以實際上會有N個邏輯。這個循環與實現無關。它甚至可能只會混淆verilog編譯器吐出一些奇怪的東西並影響仿真(其中CPU週期很重要,高於答案將是有效的)。有更多工具經驗的人可以對此發表評論。

+0

鑑於「靈感來自硬件設計」的措辭(意味着它不是硬件設計)以及關於嵌入式系統的評論,我確信原始海報是問C版本是否有用。但你說得對,值得澄清。 –

+0

對,我以爲別人沒有,但看起來我沒有仔細閱讀這個問題... – Stefan

+0

@Stefan 我剛剛在大學做了一門名爲'帶FPGA的高性能計算'的課程。但我還沒有任何有關FPGA或電子設計或Verilog的知識。我只是好奇而已。它涵蓋了一些有趣的東西,如加法器,乘法器,分頻器,求冪電路。對於電氣工程師來說可能是微不足道的。 起初,當我不得不計算一些我剛剛創建的** reg [n:0] cnt **時,我增加了如** cnt <= cnt + 1 **。對我來說,** + **不是很明顯是調用加法器電路。然後我學到了這個移位寄存器的東西,那是從哪裏來的。 – Stiggo

2

(可根據Stefan的回答,我假設你問有關Verilog的版本激發了C版,不是用Verilog這樣做。)

在很多平臺上,這其實更糟,因爲移位需要一個額外的指令,而循環變量的添加是完全空閒的。

完全?

是的。因爲在許多體系結構中都有單個指令遞減計數器,並且如果分支非零則分支 - 而且這些指令所花的時間與任何其他比較分支指令一樣多。而如果你正在做一個轉換,那需要一個額外的指令週期。如果你的平臺沒有「比較平等和分支」的指令 - 而不是所有的指令都會變得更糟;有些使你在兩個指令中減去並比較爲零。

即使在沒有遞減比較分支指令的RISC平臺上,倒計時循環可能也會更快,因爲您可以簡單地減去(一條指令)並使用分支 - 非 - 非零指令 - 而在您的循環中,你需要一個移位(一條指令)和一個按位和(一條指令)在分支 - 如果零之前。假設你甚至有一個分支 - 如果零。

此外,對於簡單的for (i = 0; i < N; i++)循環,如果編譯器將循環更快地轉換爲「倒數至0」循環,那麼編譯器很簡單 - 您甚至不需要自己做那些聰明點。

1

遞增是一種非常特殊的情況。在大多數處理器和絕大多數RISC處理器中,移位和增量在執行時間上是相同的。事實上,在大多數架構中,另外也將不再使用。

當你把你的循環代碼習慣,優化器是likley簡單地展開循環,並使其在任何情況下更快。如果你使循環機制「不尋常」,優化器可能無法優化它。