|
![../images/main/bullet_green_ball.gif](http://img.e-com-net.com/image/info8/920574c930244e41a0137b9e6ecacd37.gif) |
Introduction // 简介 |
|
|
Every new learner's dream is to understand Verilog in one day, at least enough to use it. The next few pages are my attempt to make this dream a reality. There will be some theory and examples followed by some exercises. This tutorial will not teach you how to program; it is designed for those with some programming experience. Even though Verilog executes different code blocks concurrently as opposed to the sequential execution of most programming languages, there are still many parallels. Some background in digital design is also helpful. 每一个初学者的梦想是用一天的时间学会Verilog HDL,至少能够使用它。 下面的相关的页面是我让该梦想变为现实的尝试。后面,还会有一些理论和例子以及一些练习。 这个教程将不会教你如何编程;它是专门为那些有一定的编程经验的人设计的。 尽管Verilog HDL 可以并发执行不同的代码块,这区别于大多数编程语言的顺序执行; 任然有许多并行部分。 一定的数字电路方面的设计知识准备是有帮助的。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Life before Verilog was a life full of schematics. Every design, regardless of complexity, was designed through schematics. They were difficult to verify and error-prone, resulting in long, tedious development cycles of design, verification... design, verification... design, verification... 在Verilog HDL 之前的世界是一个充满电路图的世界。 每一个设计,不管其是否复杂,都是同电路完成设计的。这种设计进行验证和错误检测非常困难,从而导致非常冗长乏味,没完没了的设计开发周期: design, verification,design, verification again。。。。。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
When Verilog arrived, we suddenly had a different way of thinking about logic circuits. The Verilog design cycle is more like a traditional programming one, and it is what this tutorial will walk you through. Here's how it goes: 当Verilog HDL 诞生以后,我们突然间有了一种完全不同的对逻辑电路的思考方式。 Verilog HDL的设计周期与传统的编程设计周期非常相像,这也是本教程带大家学习的东西。它的内容如下: |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
- Specifications (specs) //规范说明,也可以称之为需求分析说明书
- High level design // 上层设计
- Low level (micro) design //底层设计
- RTL coding //RTL 级编码
- Verification //验证
- Synthesis. //综合
|
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
First on the list is specifications - what are the restrictions and requirements we will place on our design? What are we trying to build? For this tutorial, we'll be building a two agent arbiter: a device that selects among two agents competing for mastership. Here are some specs we might write up. 列表中第一项就是:规格说明也称之需求分析说明书,即我们的设计应受到的约束和完成的需求。 我们将构建什么?对于本教程,我们将构建两个代理的仲裁器: 一个设备在连个代理中设备选择一个主设备,即二路选择器。 下面是一些我们总结的要求说明。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
- Two agent arbiter. //二路仲裁器
- Active high asynchronous reset. //灵活度高的异步复位
- Fixed priority, with agent 0 having priority over agent 1 //固定的优先级: 代理0比代理1具有更高的优先级
- Grant will be asserted as long as request is asserted. //当请求得到保证后,授权也同样得到保证。
|
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Once we have the specs, we can draw the block diagram, which is basically an abstraction of the data flow through a system (what goes into or comes out of the black boxes?). Since the example that we have taken is a simple one, we can have a block diagram as shown below. We don't worry about what's inside the magical black boxes just yet. 一旦我们有了规格要求以后,我们可以画出框图,即系统基本的抽象数据流图(系统的数据的流入与流出)。因为我们举了一个非常简单的例子,我们可以展现该系统的框图如下.现在,我们不关心这个魔法盒子中的具体实现细节。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
![../images/main/bulllet_4dots_orange.gif](http://img.e-com-net.com/image/info8/4b203f25a9bf46a4a9fcd87915c16882.gif) |
Block diagram of arbiter //仲裁器的框图 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
![Verilog HDL In One Day Part-I_第1张图片](http://img.e-com-net.com/image/info8/e146bccbb59b46fab3746006f6cc71cb.gif) |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Now, if we were designing this machine without Verilog, the standard procedure would dictate that we draw a state machine. From there, we'd make a truth table with state transitions for each flip-flop. And after that we'd draw Karnaugh maps, and from K-maps we could get the optimized circuit. This method works just fine for small designs, but with large designs this flow becomes complicated and error prone. This is where Verilog comes in and shows us another way. 现在,如果我们不适用Verilog HDL设计这个机器,标准流程是我们画出一个状态机(state machine)。 从该状态机中,我能够找到一个真值表通过每次跳变的状态转换。接着,我们可以画出卡诺图(Karnaugh maps), 从卡诺图(K-maps)中,我能够得到优化后的电路。这种方法对于小的设计可能工作的很好;然而对于大的设计,这种工作流将变了复杂而且更容易出错。这是Verilog HDL产生的原因,同时也给我们带来了另外的一种设计方法。 总结:传统的设计方法:需求分析(specification)=》状态机=》真值表=》卡诺图(k-maps)优化=》优化电路。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
![../images/main/bulllet_4dots_orange.gif](http://img.e-com-net.com/image/info8/4b203f25a9bf46a4a9fcd87915c16882.gif) |
Low level design //底层设计 |
|
|
To see how Verilog helps us design our arbiter, let's go on to our state machine - now we're getting into the low-level design and peeling away the cover of the previous diagram's black box to see how our inputs affect the machine. 来看一下Verilog HDL 是如何帮助我们实现我们二路仲裁器的,先看一下我们的状态机。现在我们开始底层设计,揭去了前面黑盒子框图的盖子,看到输入是如何影响到这个机器的。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
![Verilog HDL In One Day Part-I_第2张图片](http://img.e-com-net.com/image/info8/db19836dfb634759b2348461e1431ff2.gif) |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Each of the circles represents a state that the machine can be in. Each state corresponds to an output. The arrows between the states are state transitions, labeled by the event that causes the transition. For instance, the leftmost orange arrow means that if the machine is in state GNT0 (outputting the signal that corresponds to GNT0) and receives an input of !req_0, the machine moves to state IDLE and outputs the signal that corresponds to that. This state machine describes all the logic of the system that you'll need. The next step is to put it all in Verilog. 每一个圆圈(cycle)代表一个机器状态(machine state )。 每个机器状态对应一个输出(output)。 机器状态间箭头(Arrow)代表状态转换,其上的标记是触发状态转换的事件。 例如,最左边的橘色的箭头的状态转换的意思是,机器在State GNT0状态下收到!req_0的输入,机器变换到state IDLE状态(和输出信号对应)。 这个状态机描述了这个系统的所有你需要的所有逻辑。 下一步就是用Verilog HDL实现它。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
|
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
![../images/main/bullet_green_ball.gif](http://img.e-com-net.com/image/info8/920574c930244e41a0137b9e6ecacd37.gif) |
Modules //模块 |
|
|
We'll need to backtrack a bit to do this. If you look at the arbiter block in the first picture, we can see that it has got a name ("arbiter") and input/output ports (req_0, req_1, gnt_0, and gnt_1). 做之前,我先回顾一下。 如果我看前面的框图,它有个名字arbiter 和输入、输出端口(req_0, req_1, gnt_0, gnt_1). |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Since Verilog is a HDL (hardware description language - one used for the conceptual design of integrated circuits), it also needs to have these things. In Verilog, we call our "black boxes" module. This is a reserved word within the program used to refer to things with inputs, outputs, and internal logic workings; they're the rough equivalents of functions with returns in other programming languages. 因为Verilog HDL 是一种从概念级设计集成电路的硬件描述语言,它同样需要这些组成部分。在Verilog HDL中,我们称这个黑盒子为module。 module 是Verilog HDL 语言编程中的保留字,用来表示输入、输出和内部工作逻辑;它们和其他语言中带有返回值的函数的功能近似等价。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
![../images/main/bulllet_4dots_orange.gif](http://img.e-com-net.com/image/info8/4b203f25a9bf46a4a9fcd87915c16882.gif) |
Code of module "arbiter" // arbiter模块的编码 |
|
|
If you look closely at the arbiter block we see that there are arrow marks, (incoming for inputs and outgoing for outputs). In Verilog, after we have declared the module name and port names, we can define the direction of each port. (version note: In Verilog 2001 we can define ports and port directions at the same time) The code for this is shown below. 你如果仔细观察arbiter模块的代码,我们看到有箭头上的符号标记(进入方向为输入,离开方向为输出)。 在Verilog HDL中,在我声明了module名字和端口名字后,我们可以定义每一个端口的方向(输入、输出)。note:(在Verilog 2001中 我们可以同时定义端口和端口的方向)。仲裁器arbiter module的模块的编码展示如下: |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
1 module arbiter (
2 // Two slashes make a comment line.
3 clock , // clock
4 reset , // Active high, syn reset
5 req_0 , // Request 0
6 req_1 , // Request 1
7 gnt_0 , // Grant 0
8 gnt_1 // Grant 1
9 );
10 //-------------Input Ports-----------------------------
11 // Note : all commands are semicolon-delimited
12 input clock ;
13 input reset ;
14 input req_0 ;
15 input req_1 ;
16 //-------------Output Ports----------------------------
17 output gnt_0 ;
18 output gnt_1 ;
You could download file one_day1.v here |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Here we have only two types of ports, input and output. In real life, we can have bi-directional ports as well. Verilog allows us to define bi-directional ports as "inout." 这里只有两类port类型: input 和output。 在真正的编程中,我们也可以声明双向(bi-direction)的端口。Verilog HDL允许我们定义双向端口的类型为:inout。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Bi-Directional Ports Example - //双向端口的例子 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
inout read_enable; // port named read_enable is bi-directional //名字为read_enable的端口为双向端口。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
How do you define vector signals (signals composed of sequences of more than one bit)? Verilog provides a simple way to define these as well. 我们如何定义一个信号组(信号矢量, vector signals, 由多于1bit的信号序列组成)。 Verilog HDL也提供一种简单的定义信号组的方式。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Vector Signals Example - //信号数组举例 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
inout [7:0] address; //port "address" is bidirectional //address 端口是一个8位的双向信号数组 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Note the [7:0] means we're using the little-endian convention - you start with 0 at the rightmost bit to begin the vector, then move to the left. If we had done [0:7], we would be using the big-endian convention and moving from left to right. Endianness is a purely arbitrary way of deciding which way your data will "read," but does differ between systems, so using the right endianness consistently is important. As an analogy, think of some languages (English) that are written left-to-right (big-endian) versus others (Arabic) written right-to-left (little-endian). Knowing which way the language flows is crucial to being able to read it, but the direction of flow itself was arbitrarily set years back. 注意:[7:0]意味着使用的是小端模式的约定。 以最右边的bit位作为第0位,向左依次增加。 [0:7]意味着将使用大端模式的约定,以最左边的bit位作为第0位,依次向右增加。 字节顺序(大小端问题)是一个完全的专制的方式决定着你怎样读取数据。但是,不同的系统有可能不同,所以正确的字节顺序的一致性,是至关中要的。 一个比拟是,英语English的书写顺序是left-to-right(从左到右,采用的big-endian),然而Arabic书写则是right-to-left(little endian)。 确定那种方式语言流采用的的是至关重要的,但是几年前流的方向是可以任意设置的。 译者注:有点乱呀,关于大小端字节序的问题:C语言中,小端模式:低位字节,在低地址;而大端模式中,低位字节在高地址; 8位信号组中,least significant bit在最右端,最低位bit在least-significant-bit位的小端;最低位在most-significant bit位为大端模式; |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Summary //总结 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
- We learnt how a block/module is defined in Verilog. // 学习了Verilog中定义块(module)的方法
- We learnt how to define ports and port directions. //学习了如何定义端口和端口方向的方法
- We learnt how to declare vector/scalar ports. //学习了声明矢量和标量端口
|
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
![../images/main/bullet_green_ball.gif](http://img.e-com-net.com/image/info8/920574c930244e41a0137b9e6ecacd37.gif) |
Data Type //数据类型 |
|
|
What do data types have to do with hardware? Nothing, actually. People just wanted to write one more language that had data types in it. It's completely gratuitous; there's no point. data type(数据类型) 与硬件有什么关系呢? 事实上,没有任何关系。人们只是想写另外一种有类型的语言。 它是完全免费的,没有意义的。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
But wait... hardware does have two kinds of drivers. //但是,等一下,硬件确实有两种类型的传输驱动。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
(Drivers? What are those?) //驱动?它们是什么? |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
A driver is a data type which can drive a load. Basically, in a physical circuit, a driver would be anything that electrons can move through/into. 一个驱动器是一种数据类型,能够驱动一种负载。基本上讲,在一个物理电路中,驱动器是一个电子可以进出的部件。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
- Driver that can store a value (example: flip-flop). //驱动器可以存储一个值(例如:触发器 flip-flop)
- Driver that can not store value, but connects two points (example: wire). //驱动器也可以不用来存储值,而是用来连接两个点。(如:wire 线类型)
|
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
The first type of driver is called a reg in Verilog (short for "register"). The second data type is called a wire (for... well, "wire"). You can refer to tidbits section to understand it better. 在Verilog HDL中,第一种驱动类型称之为reg (register的简写), register寄存器类型。 第二种数据类型称之为wire, 即线类型。 你可以参考先关的资料部分跟深入地理解它。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
There are lots of other data types - for instance, registers can be signed, unsigned, floating point... as a newbie, don't worry about them right now. 有许多其他的数据类型,如 register可以分为signed, unsigned, floating point。。。现在,作为一个新手不必关心它们的细节。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Examples : //举例 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
wire and_gate_output; // "and_gate_output" is a wire that only outputs //and_gate_output是一种wire类型的输出 |
|
|
reg d_flip_flop_output; // "d_flip_flop_output" is a register; it stores and outputs a value // d_flip_flop_output是一种register类型,用来存放D触发器的输出。 |
|
|
reg [7:0] address_bus; // "address_bus" is a little-endian 8-bit register //采用小端模式的8-bit register类型 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Summary //总结 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
- Wire data type is used for connecting two points. //线类型用来连接两个点
- Reg data type is used for storing values. //寄存器数据类型用来存放值
- May god bless the rest of data types. You'll see them someday. 愿上帝保佑其他数据类型,我们将来会遇见它们。
|
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
![../images/main/bullet_green_ball.gif](http://img.e-com-net.com/image/info8/920574c930244e41a0137b9e6ecacd37.gif) |
Operators //操作符 |
|
|
Operators, thankfully, are the same things here as they are in other programming languages. They take two values and compare (or otherwise operate on) them to yield a third result - common examples are addition, equals, logical-and... To make life easier for us, nearly all operators (at least the ones in the list below) are exactly the same as their counterparts in the C programming language. 感谢上帝,操作符和其他编程语言中操作符是一样的。 它们使用两个值并且比较它们(或者其他操作)来产生第三个结果,典型的例子如addition,equals, logical-and.... 为了是生活变得更方便,几乎所有的操作符(至少下面这个列表中的)和C编程语言中的对应部分是完全一样的。 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Operator Type |
Operator Symbol |
Operation Performed |
Arithmetic |
* |
Multiply |
|
/ |
Division |
|
+ |
Add |
|
- |
Subtract |
|
% |
Modulus |
|
+ |
Unary plus |
|
- |
Unary minus |
Logical |
! |
Logical negation |
|
&& |
Logical and |
|
|| |
Logical or |
Relational |
> |
Greater than |
|
< |
Less than |
|
>= |
Greater than or equal |
|
<= |
Less than or equal |
Equality |
== |
Equality |
|
!= |
inequality |
Reduction |
~ |
Bitwise negation |
|
~& |
nand |
|
| |
or |
|
~| |
nor |
|
^ |
xor |
|
^~ |
xnor |
|
~^ |
xnor |
Shift |
>> |
Right shift |
|
<< |
Left shift |
Concatenation |
{ } |
Concatenation |
Conditional |
? |
conditional |
|
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
Example - //举例 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
- a = b + c ; // That was very easy
- a = 1 << 5; // Hum let me think, ok shift '1' left by 5 positions.
- a = !b ; // Well does it invert b???
- a = ~b ; // How many times do you want to assign to 'a', it could cause multiple-drivers.
|
|
|
Summary // 总结 |
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |
|
|
- Let's attend the C language training again, they're (almost) just like the C ones.
- 让我们从新参加一次C语言的培训,它们是如此相像,就像C一样。
|
|
|
![space.gif](http://img.e-com-net.com/image/info8/06f519ae70fb41ceb2dbbb1f9a3b4fe5.jpg) |