FPGA程式設計從零開始 使用Verilog

qinghuawenkang發表於2018-10-22

FPGA程式設計從零開始
使用Verilog
[美] 西蒙 • 蒙克(Simon Monk) 著
李楊 別志松 譯
北 京
Simon Monk
Programming FPGAs: Getting Started with Verilog
EISBN:978-1-25-964376-7
Copyright © 2017 by McGraw-Hill Education.
All Rights reserved. No part of this publication may be reproduced or transmitted in any form or
by any means, electronic or mechanical, including without limitation photocopying, recording,
taping, or any database, information or retrieval system, without the prior written permission of
the publisher.
This authorized Chinese translation edition is jointly published by McGraw-Hill Education and
Tsinghua University Press Limited. This edition is authorized for sale in the People’s Republic of
China only, excluding Hong Kong, Macao SAR and Taiwan.
Translation copyright © 2018 by McGraw-Hill Education and Tsinghua University Press Limited.
版權所有。未經出版人事先書面許可,對本出版物的任何部分不得以任何方式或途徑複製或傳播,
包括但不限於影印、錄製、錄音,或透過任何資料庫、資訊或可檢索的系統。
本授權中文簡體字翻譯版由麥格勞-希爾(亞洲)教育出版公司和清華大學出版社有限公司合作出版。
此版本經授權僅限在中國大陸地區銷售、不能銷往中國香港、澳門特別行政區和台灣地區。
版權©2018 由麥格勞-希爾(亞洲)教育出版公司與清華大學出版社有限公司所有。
北京市版權局著作權合同登記號 圖字:01-2018-0334
本書封面貼有 McGraw-Hill Education 公司防偽標籤,無標籤者不得銷售。
版權所有,侵權必究。侵權舉報電話:010-62782989 13701121933
圖書在版編目(CIP)資料
FPGA 程式設計從零開始 使用 Verilog / ( ) 西蒙 蒙克 (Simon Monk) 著;李楊,別志松 譯 . —北
京:清華大學出版社,
2018
書名原文: Programming FPGAs: Getting Started with Verilog
ISBN 978-7-302-50134-3
. F … Ⅱ . ①西… ②李… ③別… Ⅲ . ① 可程式設計序邏輯器件-系統設計 Ⅳ . ① TP332.1
中國版本圖書館 CIP 資料核字 (2018) 112346
責任編輯:王 軍 韓宏志
裝幀設計:孔祥峰
責任校對:曹 陽
責任印製:宋 林
出版發行:清華大學出版社
網 址:

地 址:北京清華大學學研大廈 A 座 郵 編: 100084
社 總 機: 010-62770175 郵 購: 010-62786544
投稿與讀者服務: 010-62776969 c-service@tup.tsinghua.edu.cn
質 量 反 饋: 010-62772015 zhiliang@tup.tsinghua.edu.cn
印 裝 者:北京嘉實印刷有限公司
經 銷:全國新華書店
開 本:
148mm × 210mm 印 張: 6.125 字 數: 153 千字
版 次:
2018 7 月第 1 版 印 次: 2018 7 月第 1 次印刷
定 價:
49.80
——————————————————————————————————————————
產品編號:
078173-01
譯 者 序
Verilog 是最流行的硬體描述語言之一,已被 IEEE 列為標準硬體
描述語言。其基本語法與 C 語言相近,這一設計初衷使其對於數字電
路研發者更容易理解和上手。
本書作者 Simon Monk 博士是數位電路工程設計領域的專家,撰
寫了多本有關開源硬體方面的著作。本書是 Simon Monk 博士的經典
之作,對於使用 Verilog 語言進行 FPGA 開發的初學者來說,是一本絕
佳的入門書籍。雖然對於大部分初學者來說,數位電路設計晦澀難懂,
硬體程式設計和除錯也難以入門,但本書由淺入深、循序漸進,將複雜的
主題講得簡單易懂,將枯燥的技術講得活靈活現;從基本的數位電路
概念講起,全面介紹使用 Verilog 進行 FPGA 程式設計的重要環節,指導你
開始使用 Mojo、Papilio One 和 Elbert 2 這三種流行的 FPGA 開發板。
本書雖然簡短,但麻雀雖小,五臟俱全,你將從頭到尾為大量工程編
寫指令,包括 LED 譯碼器、計時器、單音生成器,甚至是儲存器對映
的影片顯示器。作者在該領域經驗豐富,提供了多個緊貼實用的開發
例項。相信讀者在學習完本書後,能快速設計出自己的第一個作品!
何樂而不為呢?
在這裡要感謝清華大學出版社的編輯,他們對本書的翻譯和出版
投入了很多心血,保證了本書順利付梓。本書全部章節由李楊、別志
松翻譯,參與翻譯的還有王迎、王辭等人。
對於本書,譯者在翻譯過程中始終保持謹慎的態度,但難免存在
疏漏。如有任何意見和建議,懇請廣大讀者批評指正。

作 者 簡 介
Simon Monk 擁有控制和電腦科學學士學位,以及軟體工程博
士學位。Simon 是一名全職作家,迄今已撰寫多本書籍,包括
Programming Arduino Programming Raspberry Pi Hacking
Electronics
,並參與撰寫 Practical Electronics for Inventors 。Simon 的個
人網站是 MonkMakes.com,Twitter 是@simonmonk2。

致 謝
一如既往地感謝 Linda 的耐心和支援。
感謝 TAB/McGraw-Hill 和 MPS Limited 的 Michael McCabe、Patty
Wallenburg 和他們的同事。一如往常,與如此卓越的團隊合作非常
愉快。
同時感謝 Duncan Amos 有益而全面的技術審閱。

前 言
用自己的晶片完成想做的事,豈不是一件樂事?當然,現場可編
程門陣列(Field-Programmable Gate Array,FPGA)可讓你非常接近這一
夢想。FPGA 並非為你專門設計的晶片,而是通用晶片,能被配置用
來完成你希望做的任何事情。
此外,要配置 FPGA,既可繪製原理圖,也可使用硬體定義語言
Verilog;如果你的設計是成功的,Verilog 也能用於生產真正的定製芯
片。儘管本書也將展示如何使用原理圖編輯器進行設計,但本書的重
點是指導你學習 Verilog 語言。
可根據自己的需要多次修改 FPGA 配置,使其成為原型化設計的
優秀工具。如果設計問題浮出水面,你可對裝置重新程式設計,直到消除
所有漏洞為止。當你意識到可真正配置 FPGA 來包含能執行程式的處
理器時,這種十分出奇的靈活性就會顯現出來。
在本書中,你將學習 FPGA 的一般使用原則,將學習本書描述的
示例,並在三種最流行的 FPGA 評估板(Mojo、Papilio One 和 Elbert 2)
上執行這些示例。
儘管從邏輯上講,微控制器可勝任 FPGA 能完成的大部分工作,
但 FPGA 的執行速度更快;另外,一些人員發現,相對於實現複雜的
演算法,描述邏輯閘和硬體更簡單。你可使用 FPGA 實現微控制器或其
他處理器(以及其他人的工作)。
在其中一種低成本 FPGA 開發板上使用 Verilog 程式設計,可能最令人
信服的原因僅在於學習一些新知識,收穫一些樂趣!

VIII Photon 物聯網程式設計從零開始
讀者可訪問下載本書各章
的專案檔案,也可掃描封底的二維碼下載。

目 錄
第 1 章 邏輯 ................................................................................. 1
1.1 邏輯閘..................................................................................... 1
1.1.1 非門............................................................................. 2
1.1.2 與門............................................................................. 3
1.1.3 或門............................................................................. 3
1.1.4 與非門和或非門.......................................................... 4
1.1.5 異或門 ......................................................................... 5
1.2 二進位制..................................................................................... 6
1.3 新增邏輯................................................................................. 8
1.4 觸發器..................................................................................... 9
1.5 移位暫存器........................................................................... 11
1.6 二進位制計數器....................................................................... 12
1.7 小結....................................................................................... 13
第 2 章 FPGA............................................................................. 15
2.1 FPGA 的工作原理................................................................ 15
2.2 Elbert 2.................................................................................. 17
2.3 Mojo...................................................................................... 18
2.4 Papilio ................................................................................... 20
2.5 軟體設定............................................................................... 22
2.5.1 安裝 ISE .................................................................... 22
2.5.2 安裝 Elbert 軟體........................................................ 24

X FPGA 程式設計從零開始 使用 Verilog
2.5.3 安裝 Mojo 軟體......................................................... 25
2.5.4 安裝 Papilio 軟體....................................................... 26
2.6 專案檔案............................................................................... 26
2.7 小結....................................................................................... 27
第 3 章 繪製邏輯 ........................................................................ 29
3.1 資料選擇器示例 ................................................................... 29
3.1.1 步驟 1:建立一個新專案 ......................................... 30
3.1.2 步驟 2:建立一個新的原理圖.................................. 34
3.1.3 步驟 3:新增邏輯符號 ............................................. 36
3.1.4 步驟 4:連線門......................................................... 36
3.1.5 步驟 5:新增 IO 標記............................................... 37
3.1.6 步驟 6:建立使用者約束檔案...................................... 38
3.1.7 步驟 7:生成.bit 檔案............................................... 42
3.1.8 步驟 8:編寫開發板................................................. 44
3.1.9 測試結果 ................................................................... 46
3.2 一個 4 位計數器示例............................................................ 48
3.2.1 繪製原理圖................................................................ 49
3.2.2 實現約束檔案............................................................ 49
3.2.3 測試計數器................................................................ 52
3.3 小結....................................................................................... 52
第 4 章 Verilog 簡介.................................................................... 53
4.1 模組....................................................................................... 53
4.2 引線、暫存器和匯流排............................................................ 54
4.3 並行執行............................................................................... 54
4.4 數字格式............................................................................... 54
4.5 使用 Verilog 編寫的資料選擇器 .......................................... 55
4.6 使用 Verilog 編寫的計數器.................................................. 59
4.7 同步邏輯............................................................................... 62

目 錄 XI
4.8 小結....................................................................................... 62
第 5 章 模組化 Verilog ................................................................ 63
5.1 七段譯碼器........................................................................... 63
5.2 按鈕去抖............................................................................... 68
5.3 複用七段顯示器和計數器.................................................... 73
5.3.1 專案結構 ................................................................... 74
5.3.2 display_7_seg............................................................. 76
5.3.3 counter_7_seg ............................................................ 79
5.3.4 使用者約束檔案............................................................ 81
5.3.5 匯入模組原始碼........................................................ 82
5.3.6 設定頂層模組............................................................ 82
5.3.7 3 數位版本................................................................. 83
5.3.8 測試........................................................................... 83
5.4 小結....................................................................................... 84
第 6 章 計時器示例..................................................................... 85
6.1 狀態機................................................................................... 85
6.2 狀態機設計........................................................................... 87
6.3 硬體....................................................................................... 88
6.3.1 你之所需 ................................................................... 88
6.3.2 構建........................................................................... 88
6.4 模組....................................................................................... 90
6.5 使用者約束檔案....................................................................... 91
6.6 計時器模組........................................................................... 92
6.6.1 輸入和輸出................................................................ 92
6.6.2 按壓按鈕 ................................................................... 92
6.6.3 報警器例項................................................................ 93
6.6.4 建模時間和顯示........................................................ 93
6.6.5 狀態機實現................................................................ 94

XII FPGA 程式設計從零開始 使用 Verilog
6.6.6 任務........................................................................... 96
6.7 測試....................................................................................... 98
6.8 小結....................................................................................... 98
第 7 章 PWM 和伺服電機........................................................... 99
7.1 脈衝寬度調製....................................................................... 99
7.2 PWM 模組 .......................................................................... 100
7.2.1 PWM 模組輸入和輸出............................................ 101
7.2.2 PWM 測試模組....................................................... 101
7.2.3 試一試 ..................................................................... 104
7.3 伺服電機............................................................................. 104
7.4 硬體..................................................................................... 105
7.4.1 你之所需 ................................................................. 105
7.4.2 構建......................................................................... 106
7.5 伺服模組............................................................................. 109
7.6 小結..................................................................................... 112
第 8 章 音訊 ..............................................................................113
8.1 單音生成............................................................................. 113
8.2 Mojo 的音訊輸出................................................................ 115
8.3 通用音/頻發生器 ................................................................ 116
8.3.1 單音模組 ................................................................. 116
8.3.2 tone_tester 模組 ....................................................... 118
8.3.3 測試......................................................................... 118
8.4 播放音訊檔案..................................................................... 121
8.4.1 音訊檔案 ................................................................. 121
8.4.2 RAM........................................................................ 122
8.4.3 wav_player 模組 ...................................................... 122
8.4.4 測試......................................................................... 125
8.4.5 準備自己的音訊...................................................... 125

目 錄 XIII
8.5 小結..................................................................................... 128
第 9 章 影片 ............................................................................. 129
9.1 VGA.................................................................................... 129
9.2 VGA 定時同步 ................................................................... 132
9.3 繪製矩形............................................................................. 133
9.3.1 VGA 模組................................................................ 134
9.3.2 VGA 和 Elbert 2 ...................................................... 137
9.4 使物體運動......................................................................... 138
9.5 儲存器對映顯示 ................................................................. 141
9.6 小結..................................................................................... 143
第 10 章 擴充套件內容 .................................................................... 145
10.1 模擬................................................................................... 145
10.2 更深層次的內容 ............................................................... 146
10.3 核和軟處理器................................................................... 147
10.4 更多 Papilio 內容.............................................................. 147
10.5 更多 Mojo 內容................................................................. 149
10.6 小結................................................................................... 150
附錄 A 資源.............................................................................. 151
附錄 B Elbert 2 參考................................................................. 155
附錄 C Mojo 參考..................................................................... 165
附錄 D Papilio One 參考........................................................... 173

1
邏 輯
現場可程式設計門陣列(FPGA)是依賴數字邏輯的數字裝置。計算機硬
件使用數字邏輯。每一次計算、渲染到螢幕上的每一個畫素,以及
音軌中的每一個音符都可使用數字邏輯的構件來建立。
雖然相對於物理電子器件,數字邏輯有時更像一個抽象的數學概
念,但數字邏輯的邏輯閘和其他部件是由電晶體蝕刻到積體電路
(Integrated Circuit,IC)上進行構建的。在 FPGA 中,透過繪製邏輯閘
來設計電路,然後將邏輯閘對映到 FPGA 上的通用門並連線在一起,
以實現邏輯設計。另外,也可使用 Verilog 或其他硬體描述語言來描述
邏輯。
你可購買包含少量邏輯閘的晶片,例如具有四個兩輸入 NAND 門
的 7400 晶片。然而,這些晶片實際上僅用於維護使用它們的舊系統,
或用於教學用途。
1.1 邏輯閘
邏輯閘具有輸入和輸出。這些數字輸入和輸出可以是高電平或低
電平。低數字輸入或輸出由接近 0V(接地)的電壓表徵。高數字輸入通
常超過邏輯電源電壓的一半,高數字輸出是正電源電壓。FPGA 電源
電壓通常為 1.8V、3.3V 或 5V,大部分 FPGA 可執行於一段電壓範圍

2 FPGA 程式設計從零開始 使用 Verilog
內,有些允許在一臺裝置上使用多個邏輯電壓。
邏輯閘的描述較為複雜,因為邏輯閘的名稱(非、與、或等)在英
文中也有對應的含義。為避免混淆,本書將門名稱大寫。
1.1.1 非門
最簡單的邏輯閘是非(NOT)門,有時稱為反相器。它具有單輸入
和單輸出。如果輸入是高電平,則輸出是低電平;反之亦然。圖 1-1
顯示了非門的原理圖符號。真值表列出每種可能的輸入組合及對應輸
出。按照慣例,輸入命名時,使用字母表開頭的字母,如 A、B 和 C。
輸出命名時,通常是 Q 或臨近字母表結尾處的字母,如 X、Y 和 Z。


圖 1-1 非門
為描述邏輯閘或一組邏輯閘的行為,可使用真值表。真值表定義
邏輯為每個可能的輸入或輸出組合提供的輸出。非門的真值表如表 1-1
所示。字母 H 和 L 或數字 1 和 0 用於代替高(high)和低(low)。
表 1-1 非門的真值表

輸入 輸出
L H
H L


如果將一個非門的輸出連線至第二個非門,如圖 1-2 所示,組合
電路的輸出一定為輸入本身。

圖 1-2 兩個非門

1.1.2 與門
顧名思義,與門的輸出僅在其所有輸入都為高電平時為高。圖 1-3
顯示了兩輸入與門的符號,表 1-2 是與門的真值表。

圖 1-3 與門
表 1-2 與門的真值表

輸入 A 輸入 B 輸出 Q
L L L
L H L
H L L
H H H


1.1.3 或門
顧名思義,任一輸入為高電平時,或門的輸出為高。圖 1-4 顯示
了兩輸入或門的符號,表 1-3 是或門的真值表。

圖 1-4 或門
表 1-3 或門的真值表

輸入 A 輸入 B 輸出 Q
L L L
L H H
H L H
H H H



4 FPGA 程式設計從零開始 使用 Verilog
1.1.4 與非門和或非門
圖 1-1 所示的非門輸出的小電路表明了門的反相功能。與非門
(NOT AND,NAND)是與門的輸出反相,而或非門(NOT OR,NOR)
是或門的輸出反相。圖 1-5 顯示了這兩個門的符號,表 1-4 和表 1-5
分別是這兩個門的真值表。

圖 1-5 與非門和或非門
表 1-4 與非門的真值表

輸入 A 輸入 B 輸出 Q
L L H
L H H
H L H
H H L


表 1-5 或非門的真值表

輸入 A 輸入 B 輸出 Q
L L H
L H L
H L L
H H L


與非門和或非門都作為通用門(universal gate)來描述,因為透過對
輸入和輸出的反相,二者均可作為其他型別的門使用。另外,可組合
一個與非門和一個或門的輸入形成一個非門。例如,圖 1-6 顯示瞭如

何使用三個或非門組成一個與門。

圖 1-6 使用三個或非門組成一個與門
德摩根定律
1-6 的設計使用了一條邏輯法則,稱為德摩根定律,其最佳解
釋如下:將兩個輸入“做與”後進行反相的結果等於將兩個輸入分別
反相再“做或”。在圖
1-6 中,實際有兩個輸入透過非門進行反相 (
入繫結在一起的或非門
) ,然後“做或”,門對其自身反相,整體的結
果等同於將所有輸入“做與”。這是一個有用的技巧。
可透過表 1-6 所示的真值表檢查德摩根定律,該表分別包含 A 和
B 的中間狀態,以及 A 和 B 的反相結果。
表 1-6 由或非門實現與門的真值表

輸入 A 輸入 B 非 A 非 B 輸出 Q
L L H H L
L H H L L
H L L H L
H H L L H


1.1.5 異或門
之前討論的或門是一種包含性的或運算,即 A 或 B 之一為高,或
者二者均為高時,其結果為高。在英語中,“或”的意思是排除性的或。
你想要奶油或冰淇淋作為甜點——暗指不允許同時享用二者。邏輯閘
中這種型別的或稱為異或(exclusive OR,XOR)。異或非常有用,因為
它允許對輸入進行比較。不管輸入為高或低,只要輸入不同,則異或

的輸出為高。
圖 1-7 顯示瞭如何使用四個與非門構建一個異或門。因為異或門
經常使用,在與非門符號右側顯示異或門的符號。表 1-7 顯示了異或
門的真值表。

圖 1-7 由四個與非門構建一個異或門
表 1-7 異或門的真值表

輸入 A 輸入 B 輸出 Q
L L L
L H H
H L H
H H L


1.2 二進位制
如果不把邏輯閘的輸入和輸出看成高電平或低電平,而將其認為
是數字(1 表示高電平,0 表示低電平),那麼可開始考慮計算機如何使
用邏輯閘進行數字運算。然而,僅有數字 0 和 1 並不能滿足要求。
我們使用十進位制數,即使用 10 個符號表示數字 、1、2、3、4、
5、6、7、8 和 9。這樣做可能是因為我們有 10 根手指。當我們需要表
示大於 9 的數字時,不得不使用兩個符號——10、45、99,等等。最
右邊的數(稱為最低有效數字)是個位,向左一位的數字是十位,再向
左一位是百位,依此類推。
如果我們決定利用鼻子數而不是手指數進行計數,則會使用二進
制數。你有 0 或 1。如果你想表示一個大於 1 的數字,則必須採用多

個數位。一個二進位制數字稱為“位”。通常,為了更有意義,我們需要
將幾個位組合在一起,就像需要一組十進位制陣列合在一起以表示更大
的數字一樣。
表 1-8 顯示瞭如何使用 3 位表示數字 0 至 7。注意在顯示二進位制
數字時,通常包含前面的零。
表 1-8 數字 0 至 7 的二進位制和十進位制表示

十進位制數 二進位制數
0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111


如果分解一個十進位制數,例如 123,可將其寫作 1×100+2×10+3。
如果想知道一個二進位制數的十進位制表示形式,也可使用該方法。例如,
二進位制數 111 是十進位制數 1×4+1×2+1=7。如果要將更大的二進位制數轉
換 為 十 進 制 數 , 例 如 100110 , 則 十 進 制 取 值 為
1×32+0×16+0×8+1×4+1×2 +0=38。
一個位元組是 8 位,則其數位的十進位制分別等價於 128、64、32、
16、8、4、2 和 1。如果將其相加在一起,意味著可表示 0 至 255 之間
的任意十進位制數。每次增加一位,可將表示的數字範圍加倍。數字很
快就變得很大。現代計算機每次進行 64 位運算,數字範圍從 0 一直到
將近 18 000 000 000 000 000 000。

1.3 新增邏輯
邏輯閘允許基於二進位制數進行運算。因為二進位制數是由位表示的
數,使用邏輯閘可執行任意算術運算。圖 1-8 顯示了使用邏輯閘構建
二進位制加法器。
進位輸出

圖 1-8 一位加法器
表 1-9 顯示了一位加法器的真值表。然而,此次有兩個輸出:加
和和進位。在加法運算結果太大而超出 1 位的表示範圍時,進位為 1。
表 1-9 一位加法器的真值表

輸入 A 輸入 B 輸出加和(A+B) 輸出進位
0 0 0
0 1 1
1 0 1
1 1 0 1


觀察此表會發現,如果 A 和 B 均為 ,則和為 。如果二者之一
為 1,則和為 1。然而,如果 A 和 B 均為 1,則和數位自身為 ,但我
們希望下一個數位進位為 1。在二進位制中,1+1 為 0 進 1(或二進位制 2)。
如此操作意味著,如果我們一次進行多位加和,則下一個加運算
步驟有三個輸入(A、B 和進位)。這有點複雜,因為我們不得不將三個
數相加,而不是兩個。圖 1-9 顯示了一個運算進位數的加法器步驟。

進位輸入
進位輸出

圖 1-9 帶有一個進位的一位加法器
你從不需要用多個門來建立這樣的加法器,因為在設計中加法器
可作為單個元件直接使用。然而,理解如何從基本的門組建加法器是
很有趣的。
如果我們有八個這樣的步驟,可用它們執行 2 位元組加法。每個計
算機的中央處理器(Central Processing Unit,CPU)都有硬體加法器,硬
件加法器由以類似方式實現的邏輯閘組成。32 位處理器一次能處理 32
位數,64 位處理器具有 64 階如圖 1-9 所示的加法步驟,一次加 64 位。
1.4 觸發器
在前述示例中,邏輯閘被安排為:對於給定的輸入取值集合,總
將獲得相同的輸出。如果將邏輯閘的輸出反饋給影響首個門輸入的前
列邏輯閘,將為邏輯閘網路賦予記憶功能。這類邏輯閘稱為時序邏輯
(sequential logic)。
電子器件的一個有趣之處在於,它是一個較新的領域,其先驅拋

棄早期浮誇的拉丁命名規則,將從一個狀態跳躍至另一個狀態的元件
稱為觸發器(flip-flop)。對於懷念其較無趣名稱的人們來說,也可稱其
為雙穩態(bistable)。
置位-復位觸發器

圖 1-10 所示的原理圖稱為置位-復位(Set-Reset,SR)觸發器。在引

入將高電平視為 1、低電平視為 0 的思想後,我們繼續用數字表示邏
輯值。設想開始時,S 置位為 1,R 復位為 。因為或非門 A 的一個輸
入(S)為 1,無論或非門 A 的另一輸入是否為 1,輸出都為 。或非門
A 輸出為 0 意味著,或非門 B 的頂層輸入也將為 。或非門 B(R)的另
一輸入也為 ,因此或非門 B 的輸出為 1,使得或非門 A 下面的輸入
也為 1。接下來,S 置位為 ,這對或非門 A 的輸出沒有影響。
透過將 S 置位為 1,輸出 Q 置位為 1,無論我們如何置位 S,Q
都不會改變:僅在 R 置位為 1 時才會改變,此時使得或非門 B(Q)的輸
出為 。或非門 A 的輸出標記為 Q 加上畫線。該線(稱之為條)表明對
輸出反相, Q表示對 Q 取反。

圖 1-10 置位-復位觸發器
上述 SR 觸發器只是偶爾用到,而最常用、最靈活的觸發器型別
是 D 觸發器。可透過一個與非門或者或非門構建 D 觸發器,你僅需要
將其用作邏輯塊。圖 1-11 顯示了 D 觸發器的符號。

圖 1-11 D 觸發器
D 觸發器仍有管腳 S、R、Q 和Q,但它有兩個額外的管腳 D 和
CK(時鐘)。時鐘符號通常顯示為一個小的三角凹槽。你仍可使用管腳
S 和 R 分別置位和復位觸發器,但更可能使用管腳 D 和 CK。
有時,時鐘概念對於數位電路是至關重要的。它同步系統,這樣,
邏輯閘由高位變化到低位(以及透過多徑傳播)所引起的微小時延在輸
出尚未結束時,不會引起差錯。時鐘通常連線至一個在高位和低位來
回跳變的訊號。本書在大部分示例中,FPGA 具有一個內建的時鐘信
號。該訊號為 12~50MHz,具體取決於本書示例所用的 FPGA 開發板,
每秒有 12 萬~5000 萬個高/低位時鐘週期。
當時鍾訊號變為高位時,無論 D 的取值如何(0 或 1),都會被鎖定
至輸出 Q。這聽起來令人失望,但它可用於構建更常用的移位暫存器
和計數器。下面將介紹移位暫存器和計數器。
1.5 移位暫存器
圖 1-12 顯示了四個 D 觸發器,前一個 D 觸發器的輸出 Q 作為與
其連線的後一個 D觸發器的輸入。D觸發器的所有時鐘都連線在一起。
這樣的佈置稱為序列-並行移位暫存器。

圖 1-12 使用 D 觸發器的 4 位序列-並行移位暫存器
假設時鐘和 D 都連線到按壓開關,QA 和 QD 均連線到發光二極
管(Light-Emitting Diode,LED),LED 在高位時點亮。按壓 D 開關(使
其處於高位),在短暫按壓時鐘開關時,D 的高位將鎖定到第一個觸發
器。釋放 D 開關(使其處於低位),在重新短暫按壓時鐘時,將同時發
生兩件事情:
(1) QA(高位)的值將被鎖定到第二個觸發器,使 QB 為高。
(2) D(低位)的當前值將被鎖定到第一個觸發器,使 QA 為低。
每次脈衝調節時鐘為高時,位模式將向右連續輸入觸發器。注意
時鐘從 0 變為 1 時,觸發位模式向右輸入。可隨意新增更多 D 觸發器。
1.6 二進位制計數器
D 觸發器是非常靈活的元件。將上一個觸發器的反相輸出 Q 連線
至下一個觸發器作為時鐘輸入(如圖 1-13 所示),觸發器將進行二進位制
計數。
每次時鐘訊號改變時,觸發器 A 在 0(低)和 1(高)之間切換狀態。
觸發器的輸出以半頻為下一階段提供脈衝,依此類推。這也是將計數
器稱為分頻器的原因。因此,如果時脈頻率為 24MHz,QA 的頻率將
為 12MHz,沿電路佈線類推,每次減半。

圖 1-13 將 D 觸發器用作計數器分頻器
數字手錶和時鐘通常執行在 32.768kHz 的時脈頻率上。之所以選
擇這一頻率,是因為如果進行兩個 15 次分頻,則頻率為 1Hz(每秒 1
個脈衝)。在第 3 章和第 4 章中,你將在自己的 FPGA 開發板上實現計
數器示例,首先將其繪製為類似圖 1-13 的原理圖,然後編寫數行
Verilog 程式碼。
1.7 小結
透過本章的學習,你對廣泛而複雜的數位電路領域有了初步認識。
在後續各章,你將接觸各種型別的數字器件。
在使用 FPGA 時,理解數位電路基礎知識是十分重要的;不過,
即使你不精確理解在軟體門級別建立的電路,也可使用諸如 Verilog
的語言建立複雜的設計。在第 2 章,你將瞭解 FPGA 到底是什麼,並
接觸本書使用的 FPGA 開發板:Elbert V2、Mojo 和 Papilio。

5
模組化 Verilog
設計一個複雜的 FPGA 系統時,將所有 Verilog 程式碼放入一個模組
未嘗不可。但分治更便於他人理解你所實現的例項。這是因為他們可
推斷子模組的角色,並在實際執行每個模組前看到一個更宏大的場景,
即所有這些模組組合在一起的功能。將例項分為小模組,更便於將你
在一個專案中使用的模組應用於其他專案,或將其共享給他人以便在
他們的專案中使用。
建立包含多個模組的專案時,通常有一個頂層模組。頂層模組將
所有子模組以及與 UCF 關聯的模組放在一起。與 UCF 關聯的模組用
於對映設計中的 FPGA 訊號 IO 管腳。
本章首先使用七段譯碼器模組和第 4 章介紹的計數器模組,並擴
展該示例,直到最終實現一個簡單的十進位制計數器,能在按下 UP 和
DOWN 開關時,在七段多數位顯示器上加減計數。
既可使用此處的指令組建專案,也可從 GitHub 下載完整專案,如
第 2 章末尾處所述。
5.1 七段譯碼器
我們要組建的第一個可重用模組是一個七段譯碼器。它有 4 位輸
入。輸入的數字(即數字 0 至 9)會被譯碼至正確的段位模式,並在七段

顯示器上顯示。
圖 5-1 顯示了七段顯示器的組織方式。每一段都給定 A~G 之間的
一個字母,並連線至 DP (Decimal Point)。
建立一個新專案,命名為 decoder_7_seg。也可從本書的下載資料
中找到該專案,名為 ch05_decoder_7_seg。

圖 5-1 七段顯示器
在 src目錄中建立一個新的 Verilog原始檔,命名為 decoder_7_seg。
在該檔案中,編寫或複製如下程式碼:
module decoder_7_seg(
input CLK,
input [3:0] D,
output reg [7:0] SEG
);
always @(posedge CLK)
begin
case(D)
4'd0: SEG <= 8'b00000011;
4'd1: SEG <= 8'b10011111;

第 5 章 模組化 Verilog 65
4'd2: SEG <= 8'b00100101;
4'd3: SEG <= 8'b00001101;
4'd4: SEG <= 8'b10011001;
4'd5: SEG <= 8'b01001001;
4'd6: SEG <= 8'b01000001;
4'd7: SEG <= 8'b00011111;
4'd8: SEG <= 8'b00000001;
4'd9: SEG <= 8'b00001001;
default: SEG <= 8'b11111111;
endcase
end
endmodule
模組開頭有一個 CLK(時鐘)輸入,因為我們想將模組與 FPGA 時
鍾同步。這裡也有一個 4 位輸入 D,包含被顯示的數字,以及一個 8
位暫存器 output 作為數位模式顯示在 LED 上。
always 塊與 CLK 同步,包含一個新構造,稱為 case 語句。case
語句是一種簡潔方法,可編寫具有相同取值條件的完整 if 語句塊。此
處的輸入 D 是 case 語句的期望取值。如果 D 為 ,則輸出段(SEG)設
定為數位模式 00000011。0 表示段位被點亮。因此,參考圖 5-1,這
表明段 A、B、C、D、E 和 F 均應被點亮,而段 G(位於中間)和 DP 不
被點亮。D 的每種取值都有單獨的數位模式。
case 語句結尾的 default 選項定義瞭如果 D 的取值未被匹配上時
SEG 被設定的模式。因為 D 有 4 位取值,這意味著超過十進位制數 9
的任意取值都會導致所有數段關閉。
該模組被設計為一個有用的部件,可在其他專案中使用。作為嘗
試,你可建立另一個使用該模組的模組,新模組也可實現其他功能,
例如禁用除 1 之外的所有數位。因此建立一個新的原始檔,命名為
seg_test,在其中編寫如下程式碼:
module seg_test(
input CLK,
input [3:0] D,

66 FPGA 程式設計從零開始 使用 Verilog
output [7:0] SEG,
output [3:0]DIGIT
);
assign DIGIT = 4'b1110;
decoder_7_seg decoder(.CLK (CLK), .SEG (SEG), .D (D));
endmodule
該模組的輸入和輸出是:
● CLK:時鐘
● D:Data,4 位,每一位都配置一個滑動開關
● SEG:8 位,每一位對應一個數段
● DIGITS:4 位,控制待使能的數字
注意如何初始化 DIGITS,以便使用 0 的反相邏輯使能第一個數
位。然後是一行非常有趣的程式碼:
decoder_7_seg decoder(.CLK (CLK), .SEG (SEG), .D (D));
這行程式碼建立一個名為 decoder 的 decoder_7_seg,“(”和“)”之
間的引數宣告瞭 decoder 連線至 seg_test 引線和暫存器的方式。“.”符
號後的名稱是譯碼器中的引數名,而括號“()”中的名稱是引數應鏈
接的 seg_test 中的 wires(引線)或 regs(暫存器)。
最後,需要為專案建立一個 UCF 檔案。下面列出 Mojo 下的 UCF
檔案,你可在本書的下載資料中找到其他開發板下相同的 UCF 檔案。
# User Constraint File for 7-seg decoder implementation
# on Mojo with IO Shield
NET "CLK" LOC = P56;
# 7-segments
NET "SEG[7]" LOC = P5;
NET "SEG[6]" LOC = P8;
NET "SEG[5]" LOC = P144;
NET "SEG[4]" LOC = P143;

NET "SEG[3]" LOC = P2;
NET "SEG[2]" LOC = P6;
NET "SEG[1]" LOC = P1;
NET "SEG[0]" LOC = P141;
# Digits
NET "DIGIT[3]" LOC = P12;
NET "DIGIT[2]" LOC = P7;
NET "DIGIT[1]" LOC = P10;
NET "DIGIT[0]" LOC = P9;
# Inputs to slide switches 0 to 3
NET "D[0]" LOC = P120 | PULLDOWN;
NET "D[1]" LOC = P121 | PULLDOWN;
NET "D[2]" LOC = P118 | PULLDOWN;
NET "D[3]" LOC = P119 | PULLDOWN;
為測試該專案,將其上傳到開發板,然後嘗試移動滑動開關得到
不同的取值。圖 5-2 顯示了該測試功能。

圖 5-2 測試七段譯碼器模組
5.2 按鈕去抖
嘗試計數器專案時,你可能注意到某個開關抖動會導致計數器跳
過一些數字。我們可建立一個去抖模組,該模組可用於使用開關的任
意專案中。
推下開關時,實際需要解決三個問題。首先,按下按鈕就其特性
而言並不會與時鐘同步。其次,我們實際上因為按鈕彈跳的機械解除
而移除了不必要的狀態轉移。最後,你實際上對按鈕由 OFF 至 ON(反
之亦然)的轉移觸發事件更感興趣,而不是對其處於 ON 或 OFF 狀態
時某個特定時間的事件感興趣。
可綜合分析這三個特點,並使用一個非常有用的模組解決它們,
該模組將一個潛在的抖動開關作為輸入,提供了一個乾淨的、同步的
按鈕的二進位制狀態,以及一對有用的附加輸出,在按鈕狀態轉移時單
個時鐘週期電平上升。你可在 debounce 專案中找到開關去抖專案。因
為這裡對程式碼進行了講解,你可能希望在 ISE 環境中將其公開。
可從 和 umich.edu/
courses/eecs270/270lab/270_docs/debounce.html 下載該程式碼。
首先將按鈕開關與使用一對暫存器的時鐘進行同步。此處列出
debouncer.v 檔案和程式碼註釋。可在下載檔案 ch05_debouncer 中找到演
示該模組用法的專案。
module debouncer(
input CLK,
input switch_input,
output reg state,
output trans_up,
output trans_dn
);
// Synchronize the switch input to the clock
reg sync_0, sync_1;
always @(posedge CLK)
begin

sync_0 = switch_input;
end
always @(posedge CLK)
begin
sync_1 = sync_0;
end
此後,在以下去抖程式碼中使用第二個暫存器(sync_1)的輸出:
// Debounce the switch
reg [16:0] count;
wire idle = (state == sync_1);
wire finished = &count; // true when all bits of count
are 1's
去抖自身透過使用一個計時器(本例中是一個 16 位計時器)來工
作。它忽略任何開關狀態的轉移,直至計時器到達最大值。在 16 位計
時器的情況下,有 65 536 個時鐘週期,Mojo 的 50MHz 時鐘下每個周
期為 65 536/50 000 000=1.3ms。在 Elbert 2 的 12MHz 時鐘下,每個周
期為 5.4ms;在 Papilio 的 32MHz 時鐘下,每個週期為 2ms。通常開關
抖動會在一毫秒內被很好地解決,對使用者來說,5.4ms 依然是一個非
常短的時間,因此在本書中使用其他開發板的情況下,該段程式碼也不
會被修改,儘管開發板的時鐘週期並不一樣。
確定計數器暫存器大小
大部分 FPGA專案都需要一個或多個計數器;在傳統程式語言中,
整數變數具有固定大小(例如 32 位或 64 位),但在 FPGA 中,每個向
量可能有不同的大小。為確定使用多少位,你需要掌握一些數學知識。
1 位計數器僅能保持最大取值範圍為 0 至 1,而 2 位計數器的取值範圍
為 0 至 3,3 位計數器為 0 至 7。計數器的取值上限為 2 的 N 次冪減 1,
N 為計數器的位數。表 5-1 可幫助你選擇特定取值所需的位數。

表 5-1 確定計數器大小

位數 最大取值(十進位制)
1 1
2 3
3 7
4 15
5 31
6 63
7 127
8 255
9 511
10 1023
11 2047
12 4095
13 8191
14 16 383
15 32 767
16 65 535
17 131 071
18 262 143
19 524 287
20 1 048 575


idle 引線的取值被設定為與 sync_1 對比狀態的結果。如果相同,
則開關不會發生狀態轉移,idle 取值為 1;否則,取值為 。與諸如 Java
和 C 的程式語言一樣,==運算子用於比較二者是否相同。
邏輯運算子&用於判斷計數器是否達到最大值。當使用多位寄存
器(如 count)時,結果是所有位元一起執行 AND操作。該狀態與 finished
引線關聯。

always @(posedge CLK)
begin
if (idle)
begin
count <= 0;
end
else
begin
count <= count + 1;
if (finished)
begin
state <= ~state;
end
end
end
主 always 塊同步至時鐘的正邊沿,如果未發生事件,復位計數為
。如果發生狀態轉移,計數器加 1。當計數器結束時,切換 state 輸
出。在 Verilog 中,~符號表示取反。
接下來定義有用的附加輸出 trans_dn 和 trans_up,它們分別在按
下和釋放按鈕時,使一個時鐘週期電平變高。這是對 idle 訊號輸出取
反、計時器是否已經“結束”以及 state 輸出一起進行 AND 操作實現
的。對於 trans_dn,則是對 state 取反,然後一起進行 AND 操作。
assign trans_dn = ~idle & finished & ~state;
assign trans_up = ~idle & finished & state;
endmodule
去抖程式碼的測試程式解釋了該模組可用於所有三個可能的輸出。
它使用兩個按壓按鈕,每個切換單獨的 LED 狀態,一個是 trans_dn(按
下按鈕),一個是 trans_up(釋放按鈕)。第三個 LED 只反映了第一個按
鈕的狀態。
module debounce(
input CLK,

input switch_a,
input switch_b,
output reg led_a,
output reg led_b,
output reg led_c
);
定義了三個引線,s_a_dn(按下開關 a)、s_b_up 和 s_a_state。這些
引線此後連結至三個去抖器 d1 至 d3。檢視三個去抖器的首行程式碼,
可看到去抖器名為 d1,括號中是一些引數。每個引數都成對出現,相
互之間用逗號隔開。第一個引數.clk(CLK)將去抖器的 CLK 訊號(領先
CLK 一個時鐘週期)連結至去抖器測試模組中使用的 CLK。
第二個引數.switch_input(switch_a)將去抖器的switch_input訊號鏈
接至 switch_a。最後一個引數.trans_dn(s_a_dn)將去抖器的輸出 trans_dn
連線至引線 s_a_dn。對其他兩個 debouncer 例項重複該過程。然而,
這些例項使用去抖器的輸出 trans_up 和 state,並將其分別連結至引線
s_b_up 和 s_a_state。
wire s_a_dn, s_b_up, s_a_state;
debouncer d1(.CLK (CLK), .switch_input (switch_a),
.trans_dn (s_a_dn));
debouncer d2(.CLK (CLK), .switch_input (switch_b),
.trans_up (s_b_up));
debouncer d3(.CLK (CLK), .switch_input (switch_a),
.state (s_a_state));
always 塊同步至時鐘的正邊沿,使用連結至三個去抖器輸出的引
線設定三個 LED。
always @(posedge CLK)
begin
if (s_a_dn)
begin
led_a <= ~ led_a;
end
if (s_b_up)
begin

led_b <= ~ led_b;
end
led_c <= s_a_state;
end
endmodule
現在你已對開關輸入計時,不必考慮該模組是如何工作的,僅在
需要開關去抖的專案中使用即可。為說明這一點,下一節將去抖器和
decoder_7_seg 模組組合成第三個模組,該模組是一個四位計數器的顯
示器(在 Elbert 2 示例中為三位計數器)。
5.3 複用七段顯示器和計數器
該示例(見圖 5-3)顯示了多數位的七段顯示器。按下 Up 按鈕會增
加計數,按下 Down按鈕會將其復位為 。可在專案 ch05_counter_7_seg
中找到該示例的檔案。

圖 5-3 一個複用的七段顯示器
所有三個 FPGA 開發板都有複用的七段 LED 顯示器。Mojo 開發
板(帶有 IO Shield)和 Papilio開發板 (帶有 LogicStart MegaWing)有四位
顯示器;而 Elbert 2 開發板則有三位顯示器。在所有情況下,顯示器
引線方式大致相同。圖 5-4 顯示了 Mojo IO Shield 顯示器的原理圖;
其他開發板類似,但使用不同的管腳。
每個特定數位的數段都連線至其他數位上相同的數段。換言之,
所有的數段 A 都連線在一起,所有的數段 B 都連線在一起,依此類推。
每個數段然後透過一個電晶體(如圖 5-4 中的 R5 所示)連線,連線至一
個通用輸入輸出(GPIO)管腳。
這意味著,如果你設定 GPIO 管腳 P8 為 HIGH,則所有的數段 B
將被使能。顯然,你需要在每個數位上顯示不同數字。為此,在移至
下一個數位或設定不同的數段模式前,使用單獨的數位控制管腳和對
應數位的數段模式,依次使能每個數位。這發生得如此之快,你無法
察覺——看起來只是每個數位顯示不同的數段模式。
5.3.1 專案結構
在詳細介紹前,有必要回顧一下該專案中使用的各個模組如何互
相關聯(圖 5-5)。
模組 counter_7_seg 稱為頂層模組(稍後將詳細介紹)。開發板上的
UCF 會被關聯至此模組。該模組實現了計數器邏輯:取值增加、重置
復位以及使用其他模組執行顯示。
counter_7_seg 模組有一個 display_7_seg 例項和兩個 debouncer 實
例。display_7_seg 模組負責複用顯示器,將其重新整理,使其能顯示所有
數字。模組 display_7_seg 自身包含我們之前建立的 decoder_7_seg 模
塊。它將使用 decoder_7_seg 依次設定每個數位的數段模式。

圖 5-4 Mojo IO Shield 顯示器原理圖

圖 5-5 counter_7_seg 專案中使用的模組
5.3.2 display_7_seg
你已經學習了兩個模組 decoder_7_seg 和 debouncer(去抖器),因
此我們可以開始學習模組 display_7_seg。此處列出 display_7_seg.v 文
件及其程式碼解釋:
module display_7_seg(
input CLK,
input [3:0] units, tens, hundreds, thousands,
output [7:0] SEG,
output reg [3:0] DIGIT
);

除了一個 CLK 訊號,該模組還有四個輸入(Elbert 2 開發板中是三
個輸入)用於每個數位,即個位、十位、百位、千位。兩個輸入用於
GPIO 管腳,配置為控制數段和數位使能引線。
需要三個向量:
● digit_data 是一個 4 位暫存器,被賦值為一個 4 位數字,然後
被譯碼為當前待處理的數位。
● digit_posn 是一個 2 位計數器,用於跟蹤待顯示的數位。
● prescaler 是一個 24 位計數器,用於將 CLK 輸入分頻,設定刷
新速率。前置分頻器(prescaler)並不需要 24 位那麼多,但是這
給了我們一個選用更快 FPGA 的機會。
reg [3:0] digit_data;
reg [1:0] digit_posn;
reg [23:0] prescaler;
接下來,display_7_seg 模組需要一個 decoder_7_seg 例項,從而將
一個 4 位數字轉換為一個 8 位數段模式。我們只需要其中一個例項,
因為它會被依次用於每個數位。
譯碼器的輸入 D 被連線至 digit_data,SEG 向量被重新傳遞給譯
碼器:
decoder_7_seg decoder(.CLK (CLK), .SEG (SEG), .D
(digit_data));
現在是 always 塊,其與時鐘同步。這對前置分頻器計數器加 1。
如果 prescaler 已達 50 000,則需要重新整理下一數位。Mojo 開發板 50MHz
的時鐘速率意味著每毫秒都會發生該事件。因此四位需要 4ms,重新整理
頻率為 250Hz,這依然很快,人眼無法識別。如果真的需要,可改變
取值,以匹配其他開發板的時脈頻率,但即便是 Elbert 2 的 12MHz 的
時鐘,重新整理頻率也是快得難以察覺。
always @(posedge CLK)
begin
prescaler <= prescaler + 24'd1;

if (prescaler == 24’d50000) // 1 kHz
begin
如果前置分頻器已經達到其下次數位重新整理的設定取值和時間,則
需要一系列更新,以便轉換到合適的數位資料。
首先將前置分頻器重置為 ,對下一次數位重新整理開始計時,此後
digit_posn 遞增。如果 digit_posn 為 ,則 digit_data 設定為個位。數位
控制管腳(DIGIT)之後被設定為僅使能第一個數位。此時,使用二進位制
模式 1110。因為數位控制管腳是“LOW 有效”,所以是 1110 而非 0001。
0 意味著該數位被使能。
對其他數位重複相同的模式:
prescaler <= 0;
digit_posn <= digit_posn + 2'd1;
if (digit_posn == 0)
begin
digit_data <= units;
DIGIT <= 4'b1110;
end
if (digit_posn == 2'd1)
begin
digit_data <= tens;
DIGIT <= 4'b1101;
end
if (digit_posn == 2'd2)
begin
digit_data <= hundreds;
DIGIT <= 4'b1011;
end
if (digit_posn == 2'd3)
begin
digit_data <= thousands;
DIGIT <= 4’b0111;
end
end
end
endmodule

2 位 digit_posn 計數器會自動由 3 至 0 環回處理,因此不需要單獨
復位。Elbert 2 只有三個數位,所以 digit_posn 計數器在第三個數位被
顯示後,復位為 。
5.3.3 counter_7_seg
counter_7_seg 模組是頂層模組,將所有模組整合整合。該模組的
引數均連線至 GPIO 管腳,並對映至 UCF 檔案中定義的網表。此處列
出 counter_7_seg.v 檔案及其程式碼解釋:
module counter_7_seg(
input CLK,
input switch_up,
input switch_clear,
output [7:0] SEG,
output [3:0] DIGIT
);
該專案需要兩個按壓開關,一個增量計數,一個將顯示器清除為
0000。這些開關被連結至引線,並使用去抖模組進行去抖。
wire s_up, s_clear;
debouncer d1(.CLK (CLK), .switch_input
(switch_up), .trans_dn (s_up));
debouncer d2(.CLK (CLK), .switch_input (switch_clear),
.trans_dn (s_clear));
需要四個 4 位暫存器,每個暫存器對應四個數位中的一個。
reg [3:0] units, tens, hundreds, thousands;
display_7_seg例項被引接至CLK和四位暫存器,還引接至SEG和
DIGIT;SEG和DIGIT連線至控制數段和數位選擇的FPGA GPIO管腳:
display_7_seg display(.CLK (CLK),
.units (units), .tens (tens),
.hundreds (hundreds), .thousands (thousands),
.SEG (SEG), .DIGIT (DIGIT));

大部分事件發生在 always 塊中。它檢查是否按壓了去抖開關
s_up。如果按壓,則個位加一。之後是一個更深層次的 if 語句序列,
確定數位是否溢位,如果溢位,則對下一個數位進一,然後將當前數
位復位為 :
always @(posedge CLK)
begin
if (s_up)
begin
units <= units + 1;
if (units == 9)
begin
units <= 0;
tens <= tens + 1;
if (tens == 9)
begin
tens <= 0;
hundreds <= hundreds + 1;
if (hundreds == 9)
begin
hundreds <= 0;
thousands <= thousands + 1;
end
end
end
end
如果按下 Clear 開關,則所有四個數位都被清 :
if (s_clear)
begin
units <= 0;
tens <= 0;
hundreds <= 0;
thousands <= 0;
end
end
endmodule

宣告位數及基數
如果你目光敏銳,會注意到我在賦值 0 1 時,數字格式有些不
連貫。有人會說你應該宣告位數和基數。實際上,這是個好習慣,但
對於上述這類簡短例項,也無關緊要。
ISE 會自動調整常數的位數,
以匹配被賦值的向量,而數字
1 0 在任意基數中都是相同的。
對於非
0 1 的數字,透過選擇位數和基數來避免任何可能的混
淆,是一個好辦法。然而,選擇十進位制基數並非有錯——要選擇保證
程式碼最易於理解的基數。
5.3.4 使用者約束檔案
你也需要一個 UCF 檔案。下面列出 Mojo 開發板下的 UCF。也可
在本書的下載檔案中找到適用於其他開發板的 UCF 檔案。
# User Constraint File for 7-seg counter on Mojo with IO
# Shield
NET "CLK" LOC = P56;
# Switches
NET "switch_up" LOC = "P137" | PULLDOWN;
NET "switch_clear" LOC = "P139" | PULLDOWN;
# 7-segments
NET "SEG[7]" LOC = P5;
NET "SEG[6]" LOC = P8;
NET "SEG[5]" LOC = P144;
NET "SEG[4]" LOC = P143;
NET "SEG[3]" LOC = P2;
NET "SEG[2]" LOC = P6;
NET "SEG[1]" LOC = P1;
NET "SEG[0]" LOC = P141;
# Digits
NET "DIGIT[3]" LOC = P12;

NET "DIGIT[2]" LOC = P7;
NET "DIGIT[1]" LOC = P10;
NET "DIGIT[0]" LOC = P9;
5.3.5 匯入模組原始碼
有幾種獲取所建立專案中的模組原始碼的方法。ISE 偶爾分不清
哪些檔案從屬於它,我找到將一個模組複製到另一個專案中的問題最
少的步驟,以該示例中的去抖器或 decoder_7_seg 為例:
(1) 建立一個新專案。
(2) 開啟作業系統檔案資源管理器,在專案目錄中建立一個 src
目錄。
(3) 在該 src 目錄中複製新增任意該專案所需的模組(debouncer.v
和 decoder_7_seg.v)。
(4) 在 ISE 中,使用 Add Source…選項,並導航至剛才新增到 src
目錄的.v 檔案。
5.3.6 設定頂層模組
ISE 中的 Design 選項卡顯示專案中所使用的模組之間的關係(如
圖 5-6 所示)。
你可在層級結構中看到所有檔案都是正確的,counter_7_seg 模組
包含兩個去抖器模組,display_7_seg 模組包含一個 decoder_7_seg 模
塊。如果仔細看,可發現 counter_7_seg 模組圖示緊挨著三個品字排列
的小方塊。這說明 counter_7_seg 模組是專案的頂層模組。
ISE通常能夠辨識頂層模組,但有時卻不能,此時你可透過右擊,
並選擇選項Set As Top Module,將特定模組指定為頂層模組。

圖 5-6 counter_7_seg 專案中所使用的模組
5.3.7 3 數位版本
不同於 Mojo 有四個數位,Elbert 2 只有三個數位,因此大部分情
況下,Elbert 版本的差異僅在於將數位從四減至三。使用三個數位的
一個後果是,在 display_7_seg 中,digit_posn 計數器達到百位時,需
要手動復位為 。
if (digit_posn == 2'd2)
begin
digit_data <= hundreds;
DIGIT <= 4'b1011;
digit_posn <= 0;
end
5.3.8 測試
組建專案,將其上傳至開發板。你會發現每次按下 Up 時,顯示
器數字會進 1,按下 Clear 按鈕時,顯示器數字復位為 。耐心地測試
所有四個數位,甚至測試 Elbert 2 開發板下的所有三個數位。
5.4 小結
本章開頭介紹 FPGA 的潛在能力。在第 6 章中,我們將重用本章
描述的模組,並繼續生成一個倒數計時器例項。該計時器例項也引入了
FPGA 系統設計中的一個關鍵概念,即狀態機。

購買地址:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26421423/viewspace-2217072/,如需轉載,請註明出處,否則將追究法律責任。

相關文章