Chisel 教程翻译 之 第二章:基本组件 of 《Digital Design with Chisel》

6 篇文章 0 订阅
2 篇文章 1 订阅

第二章目录:
2 Basic Components 9
    2.1 Signal Types and Constants . . . . . . . . . . . . . . . . . . . . . . . 9
    2.2 Combinational Circuits . . . . . . . . . . . . . . . . . . . . . . . . . 11
        2.2.1 Multiplexer . . . . . . . . . . . . . . . . . . . . . . . . . . . .12
    2.3 Registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  14
        2.3.1 Counting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
    2.4 Structure with Bundle and Vec . . . . . . . . . . . . . . . . . . . .  . 15
    2.5 Chisel Generates Hardware . . . . . . . . . . . . . . . . . . . . . .  . 18
    2.6 Exercise . . . . . . . . . . . . . . . . . . . . . . . . .  . . . . .  . 18
    
    
正文:    
    
    
2 Basic Components
2 基本组件

In this section, we introduce the basic components for digital design: combinational
circuits and flip-flops. 
在本节,我们会介绍数字逻辑设计的基本组件:组合电路和触发器。

These essential elements can be combined to build larger, more
interesting circuits.
这些基本的组件能够组合出来更大的更有意思的电路。

Digital systems in general built use binary signals, which means a single bit or signal
can only have one of two possible values. 
数字电路系统通常使用二进制信号,也就是说,一个比特位或者一个信号值只能是两种可能值中的一个。

These values are often called 0 and 1. 
这些值通常称为0和1.

However, we also use following terms: low/high, false/true, and de-asserted/asserted. These
terms mean the same two possible values of a binary signal.
然而,我们也有如下叫法:  低/高 ,假/真, 无效/有效。这些术语的意思也是二值信号中的两种可能值。

2.1 Signal Types and Constants
2.1 信号类型和常量


Chisel provides three data types to describe signals, combinational logic, and registers:
Chisel提供了3种数据类型来描述信号、组合逻辑和寄存器:

Bits, UInt, and SInt. 


UInt and SInt extend Bits, and all three types represent a vector of bits. 
而UInt和SInt扩展了Bits类型,而且,全部三种类型都代表多个比特位的一个向量。

UInt gives this vector of bits the meaning of an unsigned integer and SInt of a
signed integer.1 Chisel uses two’s complement as signed integer representation. 
UInt是用来表示无符号整数的bit的vector,而SInt是表示有符号整数。【注解1】
Chisel是使用二进制补码表示有符号整数。

Here is the definition for different types, an 8-bit Bits, an 8-bit unsigned integer, and a 10-bit signed integer:
这里罗列了不同类型定义的示例,一个是8比特的Bits类型,一个是8比特的无符号整数类型,一个是10比特的有符号整数类型:

Bits(8.W)
UInt(8.W)
SInt(10.W)

The width of a vector of bits is defined by a Chisel width type (Width). 
Vector的比特位宽度是由Chisel的宽度类型定义的,Chisel的宽度类型是Width。

The following expression casts the Scala integer n to a Chisel width, 
which is used for the definition of the Bits vector:
下面的表达式把Scala的整型值赋值给了Chisel的宽度,它用于定义一个Bits类型的vector:

n.W
Bits(n.W)

//--注解----start------------------------------------
The type Bits in the current version of Chisel is missing operations and therefore not very useful for user code.
Bits数据类型在当前的Chisel版本中已经扔掉了,因为它没大有用。
//--注解------end----------------------------------

Constants can be defined by using a Scala integer and converting it to a Chisel type:
常量类型可以以用Scala的整型来定义,然后转换成Chisel的类型:
0.U // defines a UInt constant of 0//无符号整数常量0

-3.S // defines a SInt constant of -3//有符号整数常量-3

Constants can also be defined with a width, by using the Chisel width type:
定义常量时,可以同时定义它的宽度,只需要更上Chisel的宽度限定符就可以了:

8.U(4.W) // An 4-bit constant of 8//用4比特宽度定义的一个无符号整数常数8

If you find the notion of 8.U and 4.W a little bit funny, consider it as a variant of an
integer constant with a type. 
如果你觉得8.U和4.W这些做法挺搞的,那么你可以把它们看成是带类型的整型常量的变体。

This notation is similar to 8L, representing a long integer constant in C, Java, and Scala.
这个标识符跟8L这种写法很相似,8L在C语言、Java和Scala中表示一个长整型常量。

Possible pitfall: One possible error when defining constants with a dedicated width is
missing the .W specifier for a width. 
可能的陷阱:一个可能会犯的错误是,在定义一个常量时,宽度限定符写的不对,可能会漏掉.W有时.


E.g., 1.U(32) will not define a 32-bit wide constant representing 1. 
比如,1.U(32)并不能正确定义一个32位宽的整型常量1.

Instead, the expression (32) is interpreted as bit extraction from position
32, which results in a single bit constant of 0. 
这个写法会被编译器解释成从1.U的第32bit索引处取出一比特的值,也就是一个比特的常量0.

Probably not what the original intention of the programmer was.
这可能不是程序员本来要表达的意思。

Chisel benefits from Scala’s type inference and in many places type information can be left out. 
Chisel是从Scala的类型推理中受益的,所以,在很多地方,数据的类型信息是可以不用写的。

The same is also valid for bit widths. 
这对bit宽度是有效的。

In many cases, Chisel will automatically infer the correct width. 
在很多情景,Chisel将会自动的推断出正确的宽度。

Therefore, a Chisel description of hardware is more concise and better readable than VHDL or Verilog.
因此,一个Chisel描述的电路硬件,是更加简洁的,而且可读性比VHDL和Verilog都更好。

For constants defined in other bases than decimal, the constant is defined in a string
with a preceding h for hexadecimal (base 16), o for octal (base 8), and b for binary (base 2). 
对于常量的定义,如果定义不带小数,常量定义在一个字符串里的,而且带着前缀,如果前缀是h,表示十六进制;
如果前缀是o则表示八进制;如果是b则表示二进制。

The following example shows the definition of constant 255 in different bases.
下面的示例展示了无符号常量255的不同进制的定义方式。

In this example we omit the bit width and Chisel infers the minimum width to fit the
constants in, in this case 8 bits.
在这个示例中,我们忽略了比特宽度,而且,Chisel会推断出最小的位宽来适配这些常量,在这个示例中的适配宽度位8比特。


"hff".U // hexadecimal representation of 255
"o377".U // octal representation of 255
"b1111_1111".U // binary representation of 255

The above code shows how to use an underscore to group digits in the string that represents a constant. 
在上述二进制的示例中展示了怎么样使用一个下划线来分组数据。

The underscore is ignored.
这个下划线会被忽略。

To represent logic values, Chisel defines the type Bool.
Chisel中,用Bool来表示逻辑类型的值。 

Bool can represent a true or false value. 
Bool可以代表逻辑真或者逻辑假。

The following code shows the definition of type Bool and the definition of Bool constants, 
by converting the Scala Boolean constants true and false to Chisel Bool constants.
下面的代码展示了Bool类型的定义和Bool型常量的定义,它是通过把Scala的布尔型常量true和false转换成Chisel的布尔型常量的。
//--Chisel代码-----
Bool()
true.B
false.B


Figure 2.1: Logic for the expression (a & b) | c. The wires can be a single bit or
multiple bits. The Chisel expression, and the schematics are the same.
Figure 2.1: (a & b) | c 的逻辑表示。
图中的信号线可以是一比特的,也可以是多个bit的。Chisel表达式,和电路图都是这样。


2.2 Combinational Circuits
2.2 组合逻辑电路

Chisel uses Boolean algebra operators, as they are defined in C, Java, Scala, and several
other programming languages, to described combinational circuits: & is the AND operator and | is the OR operator. 
Chisel使用逻辑运算符来描述组合逻辑电路,就像在C、Java、Scala和很多其他编程语言中定义的含义:& 表示逻辑与,| 表示逻辑或

Following line of code defines a circuit that combines signals a and b with and gates 
and combines the result with signal c with or gates.
下面这行代码,定义了一个电路,这个电路使用一个与门组合了信号a和b,其组合结果和信号c又被一个或门组合在一起。

val logic = (a & b) | c

Figure 2.1 shows the schematic of this combinatorial expression. 
图2.1展示了这个组合表达式的电路图。

Note that this circuit may be for a vector of bits and not only single wires 
that are combined with the AND and OR circuits.
需要注意的一点,这个电路中的信号线所表达的意思,可能不仅仅是一个单独的线,他可能是一个比特位构成的矢量,然后被与门和或门组合在一起。

In this example, we do not define the type nor the width of signal logic. 
在本例中,我们既没有定义信号的类型,也没有定义逻辑信号的宽度。

Both are inferred from the type and width of the expression. 
类型和宽度会从表达式中各个量的类型和宽度中推导出来。

The standard logic operations in Chisel are:
Chisel中标准的逻辑操作有如下这些:

val and = a & b // bitwise and    //按位与
val or = a | b // bitwise or      //按位或
val xor = a ^ b // bitwise xor    //按位异或
val not = ~a // bitwise negation  //按位取反

The arithmetic operations use the standard operators:
算数运算也是使用标准的操作符:

val add = a + b // addition
val sub = a - b // subtraction
val neg = -a // negate
val mul = a * b // multiplication
val div = a / b // division
val mod = a % b // modulo operation

The resulting width of the operation is the maximum width of the operators for addition
and subtraction, the sum of the two widths for the multiplication, 
and usually the width of the numerator for divide and modulo operations.2
这些操作的运算结果的比特宽度由如下规定:加法和减法都是操作数中宽度最大的那个宽度,而乘法则是两个操作数宽度的和,
而对于除法和取模运算而言,通常是分子的宽度。

A signal can also first be defined as a Wire of some type. 
一个信号,起初可以定义成一个某种数据类型的Wire变量。

Afterward, we can assign a value to the wire with the := update operator.
在后面的设计中,我们可以通过更新操作符 := 来给它付一个值。例如:

val w = Wire(UInt())
w := a & b


A single bit can be extracted as follows:
变量中某一个单独的比特位,可以用如下方式抽取:

val sign = x(31)

A subfield can be extracted from end to start position:
变量中的一个子域,可以使用从位置索引的尾巴到开头的方式来抽取,例如:

val lowByte = largeWord(7, 0)

Bit fields are concatenated with Cat.
比特与可以使用Cat运算符来串接起来:
val word = Cat(highByte , lowByte)

Table 2.2 shows the full list of operators (see also builtin operators). 
表2.2展示了全部操作符,也可以参考网页上的内建操作符:https://github.com/freechipsproject/chisel3/wiki/Builtin-Operators


The Chisel operator precedence is determined by the evaluation order of the circuit, 
which follows the Scala operator precedence. 
Chisel运算符的优先级实际上由电路的求值顺序所决定,它们在语言中的优先级跟Scala是一样的。

If in doubt, it is always a good praxis to use parentheses.3
Table 2.2 shows various functions defined on and for Chisel data types.
如果对优先级不是很放心,那么使用小括号总是最佳的实践。
表2.2展示了多种基于Chisel数据类型的函数。

2.2.1 Multiplexer
2.2.1 多路器

A multiplexer is a circuit that selects between alternatives. 
多路器是一个从多个选项中进行选择的电路。

In the most basic form, it selects between two alternatives. 
它的最基本形式是从两个选项中选择一个。

Figure 2.2 shows such a 2:1 multiplexer, or mux for short. 
Figure 2.2 展示了一个2对1的多路器,multiplexer也可以简写为mux。

Depending on the value of the select signal (sel) signal y will represent signal a or signal b.
输出信号y的值是a的值,还是b的值,取决于选择信号sel的值。

A multiplexer can be built from logic. However, as multiplexing is such a standard
operation, Chisel provides a multiplexer,
可以用逻辑运算来表达多路器。然而,因为多路器是一个非常标准的操作,所以Chisel提供了一个多路器的定义:

val result = Mux(sel, a, b)

//-----注解---start----------------------------------
2The exact details are available in the FIRRTL specification.
具体的细节可以从FIRRTL规范中看到。https://github.com/freechipsproject/firrtl/blob/master/spec/spec.pdf

3The operator precedence in Chisel is a side effect of the hardware elaboration when the tree of hardware
nodes is created by executing the Scala operators. 
在Chisel数字逻辑设计中,通过运行Scala的运算符生成硬件节点树,所以,电路中每个运算符的优先级是硬件详细描述后所决定的。

The Scala operator precedence is similar but not identical to Java/C. 
Scala的运算符的优先级跟C/Java的运算符的优先级很相似,但是不完全一样。

Verilog has the same operator precedence as C, but VHDL has a different one. 
Verilog运算符的优先级跟C语言的一样,但是VHDL的却不同。

Verilog has precedence ordering for logic operations, 
but in VHDL those operators have the same precedence and are evaluated from left to right.
Verilog操作的优先级是位逻辑操作而设立的,但是,在VHDL中,那些运算符拥有相同的优先级,而且是从左到右组合的。

//-----注解---end--------------------------------------------------------------------

Table 2.1: Chisel defined hardware operators.


Table 2.2: Chisel defined hardware functions, invoked on v.


Figure 2.2: A basic 2:1 multiplexer.

where a is selected when the sel is true.B, otherwise b is selected. The type of sel is
a Chisel Bool; the inputs a and b can be any Chisel base type or aggregate (bundles or
vectors) as long as they are the same type.
当sel信号位true.B时,a的值被选中;否则,b的值被选中输出。sel的类型是一个Chisel Bool型的;
输入信号a和b,可以是任意的Chisel基本类型,或者是其集合体(bundles或vectors),只要它们时同一个类型的。

With logical and arithmetical operations and a multiplexer, every combinational circuit can be described. 
使用逻辑运算符、算数运算符和多路器,所有的组合逻辑电路都要给被描述出来。(类似C语言中的顺序、选择和循环结构的表达能力)

However, Chisel provides further components and control abstractions for a more elegant 
description of a combinational circuit, which are described in a later chapter.
尽管如此,Chisel提供了更多的组件和控制抽象,以便能够更加优雅地描述一个组合逻辑电路。这些内容将在后续章节中讲解。

The second basic component needed to describe a digital circuit is a state element,
also called register, which is described next.
下一个需要用来描述要给数字逻辑电路的基本组件是状态要素,也就是所谓的寄存器,将在下一节中讲解。

2.3 Registers
2.3 寄存器

Chisel provides a register, which is a collection of D flip-flops. 
Chisel提供了寄存器类型,实际上他是用D触发器堆出来的。

The register is implicitly connected to a global clock and is updated on the rising edge. 
寄存器时隐式地跟全局时钟信号相连的,而且在每个时钟周期的上升沿进行更新。

When an initialization value is provided at the declaration of the register, 
it uses a synchronous reset connected to a global reset signal. 
如果当定义一个寄存器时,给他一个初始化值,那么这个寄存器将用一个全局的同步重置信号来实现。

A register can be any Chisel type that can be represented as a collection of bits. 
一个寄存器可以是Chisel的任意类型,这些都可以用比特位的组合来表示。

Following code defines an 8-bit register, initialized with 0 at reset:
下面的代码定义了一个8-bit的寄存器,并且用0来初始化它:

 val reg = RegInit(0.U(8.W))

An input is connected to the register with the := update operator and the output of the
register can be used just with the name in an expression:
对寄存器的一次输入,使用更新操作符:=连接到寄存器上,而且,寄存器的输出只需要把寄存器的名字放到表达式中就可以了,例如:

reg := d
val q = reg

A register can also be connected to its input at the definition:
一个寄存器,也可以在定义它的同时把信号连接其上,例如:
val nextReg = RegNext(d)

Figure 2.3 shows the circuit of our register definition with a clock, a synchronous
reset to 0.U, input d, and output q. 
Figure 2.3 展示了定义一个带时钟的寄存器的电路,而且可以同步置位到0.U值,输入是d,输出是q。

The global signals clock and reset are implicitly connected to each register defined.
全局的时钟信号和重置信号都是隐式地连接到每一个定义的寄存器上的。

A register can also be connected to its input and a constant as initial value at the definition:
在定义的时候,可以将一个输入信号和一个常量作为初始化值,一并连接到寄存器上去,例如:

val bothReg = RegNext(d, 0.U)

To distinguish between signals representing combinational logic and registers, 
a common practice is to postfix register names with Reg. 
为了区分组合逻辑的信号和寄存器,一个通常的习惯做法是在寄存器变量的名字前半部分用Reg来命名。

Another common practice, coming from Java and Scala, is to use camelCase for identifier consisting of several words. 
另一个通常的习惯做法,是来自于Java和Scala的,那就是用驼峰拼写法来命名由多个单词组成的标识符。

The convention is to start functions and variables with a lower case letter and classes (types) with an upper case letter.
常规的做法是,函数名和变量名的第一个单词用小写的,而类名和类型名的第一单词的第一个字母用大写。


Figure 2.3: A D flip-flop based register with a synchronous reset to 0.


2.3.1 Counting
2.3.1 计数

Counting is a fundamental operation in digital systems.
计数是数字系统中的一个基本操作。

On might count events. However, more often counting is used to define a time interval. Counting the clock cycles
and triggering an action when the time interval has expired.
计数事件。然而,更经常使用的计数方式是定义一个事件间隔。然后,数着时钟的个数,等到时间间隔过期了,就触发一个动作。

A simple approach is counting up to a value. However, in computer science, and
digital design, counting starts at 0. 
一个简单的方法是一直书到要给给定值。然而,在计算机科学和数字电路设计中,计数是从0开始的。

Therefore, if we want to count till 10, we count from 0 to 9. 
因此,如果我们计划计数10,那么我们实际上是从0数到9.

The following code shows such a counter that counts till 9 and wraps around to 0 when reaching 9.
下面的代码展示了一个计数器,它计数最大会数到9,并且到达9后会回到0.

val cntReg = RegInit(0.U(8.W))

cntReg := Mux(cntReg === 9.U, 0.U, cntReg + 1.U)


2.4 Structure with Bundle and Vec
2.4 Bundle结构 和 Vec结构
Chisel provides two constructs to group related signals: 
Chisel提供了如下两个概念来组织相关联的信号:
(1) a Bundle to group signals of different types and 
(1)Bundle是用来组织不同类型的相关信号的结构,而且

(2) a Vec to represent an indexable collection of signals of the same type. Bundles and Vecs can be arbitrarily nested.
(2)Vec是用来表示一组相同类型的可索引的信号的。而且,Bundle和Vec结构可以任意地互相嵌套。

A Chisel bundle groups several signals. 
Chisel的bundle可以一下组织好几个信号。

The entire bundle can be referenced as a whole, or individual fields can be accessed by their name. 
一个bundle可以作为一个整体被引用,而且其单个的字段也可以通过他们的名字来访问。

We can define a bundle (collection of signals) by defining a class 
that extends Bundle and list the fields as vals within the constructor block.
我们可以通过定义一个类来定义一个bundle(也就是一组信号堆放在一起),这个类通过继承Bundle基类,
且把字段罗列在构造器中作为变量,例如:

class Channel() extends Bundle {
    val data = UInt(32.W)
    val valid = Bool()
}

To use a bundle, we create it with new and wrap it into a Wire. 
怎么样使用一个bundle子类呢? 我们把它包在一个Wire变量中定义它。

The fields are accessed with the dot notation:
它的字段通过点号来访问:

val ch = Wire(new Channel())
ch.data := 123.U
ch.valid := true.B
val b = ch.valid

Dot notation is common in object-oriented languages, 
where x.y means x is a reference to an object and y is a field of that object. 
点号操作符在OO语言中是很常见的, 比如,x.y的意思是,x是对一个对象的引用,而y是这个对象的一个字段。

As Chisel is object-oriented, we use dot notation to access fields in a bundle. 
因为Chisel是OO的,所以我们用点号运算符来访问bundle子类的对象的字段。

A bundle is similar to a struct in C, a record in VHDL, or a struct in SystemVerilog. 
bundle类型跟C语言中的struct很像,跟VHDL中的record很像,或者跟SystemVerilog中的struct很像。

A bundle can also be referenced as a whole:
一个bundle对象也可以作为整体被引用,例如:

val channel = ch


A Chisel Vec represents a collection of signals of the same type (a vector). 
Chisel的Vec类型 表示相同类型的一组信号堆在一起(实际上是一个vector类)。

Each element can be accessed by an index. 
每一个元素都以可以用索引来访问。

A Chisel Vec is similar to array data structures in other programing languages.4 
Chisel的Vec跟其他编程语言中的array数组数据结构很相似。

A Vec is created by calling the constructor with two parameters: the number of elements and the type of the elements. 
一个Vec对象通过调用一个带着两个参数的构造器来创建,一个参数用来表示元素的个数;另一个参数表示元素的类型。

A combinational Vec needs to be wrapped into a Wire
在组合电路里,一个Vec需要用Wire包起来定义并使用它,例如:

val v = Wire(Vec(3, UInt(4.W)))

Individual elements are accessed with (index).
Vec对象中的单个元素要使用索引来访问,形如(index),例如:

v(0) := 1.U
v(1) := 3.U
v(2) := 5.U
val idx = 1.U(2.W)
//---注解-------start-------------------
The name Array is already used in Scala.
Array这个关键字在Scala中已经被使用了。
//---注解-------end-------------------

val a = v(idx)

A vector wrapped into a Wire is a multiplexer. 
包进Wire中的vector实际上是一个多路器。

We can also wrap a vector into a register to define an array of registers. 
我们也可以把一个vector对象包进一个寄存器中,来定义一个寄存器array数组

Following example defines a register file for a processor; 
32 registers each 32-bits wide, as for a classic 32-bit RISC processor, like the 32-bit version of RISC-V.
下面的示例为一个处理器定义了一个寄存器文件;32个32bit的寄存器,为一个32位的RISC处理器,就像32-bit版本的RISC-V。
val registerFile = Reg(Vec(32, UInt(32.W)))

An element of that register file is accessed with an index and used as a normal register.
这个寄存器文件的一个元素可以用一个索引来访问,而且可以当作普通的寄存器来使用,读写寄存器文件的元素如下所示:

registerFile(idx) := dIn
val dOut = registerFile(idx)

We can freely mix bundles and vectors. 
我们可以自由地混合使用bundle和vector。

When creating a vector with a bundle type, we need to pass a prototype for the vector fields. 
当创建一个元素类型位bundle的vector时,我们需要为vector的字段传递一个原型。

Using our Channel, which we defined above, we can create a vector of channels with:
使用我们先前定义的Channel这个bundle子类,我们可以定义一个channel元素的vector,如下:

val vecBundle = Wire(Vec(8, new Channel()))

A bundle may as well contain a vector:
一个bundle的子类也可以包含一个vector:

class BundleVec extends Bundle {
    val field = UInt(8.W)
    val vector = Vec(4,UInt(8.W))
}


When we want a register of a bundle type that needs a reset value, we first create a
Wire of that bundle, set the individual fields as needed, and then passing this bundle to a RegInit:
当我们需要某个带复位值得bundle类型的寄存器时,步骤如下,我们首先创建一个包进这个bundle的Wire,然后给bundle的这些字段赋值,
最后把这个Wire传递个一个RegInit:

val initVal = Wire(new Channel())
initVal.data := 0.U
initVal.valid := false.B
val channelReg = RegInit(initVal)

With combinations of Bundles and Vecs we can define our own data structures, which are powerful abstractions.
用Bundle和Vec的组合,我们可以定义自己的数据结构,这是很强大的抽象能力。

2.5 Chisel Generates Hardware
2.5 Chisel是设计用来生成电路硬件的,不要搞错

After seeing some initial Chisel code, it might look similar to classic programming languages such as Java or C. 
看了一些入门级的Chisel代码以后,发现它们看上去跟典型的编程语言,如Java或者C,很相似。
However, Chisel (or any other hardware description language) does define hardware components. 
然而,Chisel(或者其他任何一个硬件描述语言)是用来定义硬件组件的。

While in a software program one line of code after the other is executed, 
in hardware all lines of code execute in parallel.
然而,在软件程序中,代码是一行接一行地执行的,但是在硬件中所有的代码都是平行执行的。

It is essential to keep in mind that Chisel code does generate hardware. 
在脑袋里面绷着一根弦儿是有必要的,Chisel是用来生成硬件的。

Try to imagine, or draw on a sheet of paper, 
the individual blocks that are generated by your Chisel circuit description. 
把你的Chisel代码所描述的一个个电路,试着在头脑中想象一下,或者画在纸片上。

Each creation of a component adds hardware; each assignment statement generates gates and/or flip-flops.
每一个的创建都会增加到硬件中;每一个赋值表达式都会产生门电路或者/和触发器。

More technically, when Chisel executes your code it runs as a Scala program, and by executing the Chisel statements, 
it collects the hardware components and connects those nodes. 
更专业地说,当Chisel运行你的代码,他是作为一个Scala程序运行的;而且,通过运行Chisel表达式,
它收集了硬件组件,并且把节点连接起来了。

This network of hardware nodes is the hardware, 
which can spill out Verilog code for ASIC or FPGA synthesis or can be tested with a Chisel tester. 
这些硬件节点的网络是硬件,这些网络可以变成制作ASIC或FPGA综合的Verilog代码,而且它们可以用Chisel测试其测试。

The network of hardware nodes is what is executed in fully parallel.
这些硬件节点网络,执行起来是力求并行执行的。

For a software engineer imagine this immense parallelism that you can create in hardware 
without needing to partition your application into threads and getting the lockingcorrect for the communication.
不需要像软件程序员那样把程序分解成一个个线程,然后加很多正确的锁,在Chisel硬件上设计上就可以达到并行。


2.6 Exercise
2.6 练习


In the introduction you implemented a blinking LED on an FPGA board (from chiselexamples), 
which is a reasonable hardware Hello World example. 
在上一章介绍时,你用Chiselexamples项目中的代码,在FPGA板子上实现了一个闪烁的LED。
把它作为硬件设计中的一个Hello World级别的示例时合理的。

It used only internal state, a single LED output, and no input. 
它只使用了内部状态,一个单独的LED输出,然后并没有输入。

Copy that project into a new folder and extend it by adding some inputs to the io Bundle with val sw = Input(UInt(2.W)).
把这个代码拷贝到一个新的文件夹中,并且扩展它。在io这个Bundle结构中加入一句代码来增加一些输入信号。

val io = IO(new Bundle {
val sw = Input(UInt(2.W))
val led = Output(UInt(1.W))
})


For those switches, you also need to assign the pin names for the FPGA board. 
对于这些开关,你还需要给它们赋上FPGA板子上管脚的名字。

You can find examples of pin assignments in the Quartus project files of the ALU project 
(e.g.,for the DE2-115 FPGA board).
在Quartus项目文件的ALU项目中,你可以找到管脚名赋值的示例(例如在DE2-115 FPGA板子的项目文件夹里https://github.com/schoeberl/chisel-examples/blob/master/quartus/altde2-115/alu.qsf)。

When you have defined those inputs and the pin assignment, start with a simple test:
drop all blinking logic from the design and connect one switch to the LED output;
compile and configure the FPGA device. 
当你定义了输入信号,而且做了管脚赋值,就可以开始一个简单的测试了:
从设计中删除所有跟LED闪烁有关的逻辑,并且把其中的一个开关连接到LDE的输出上;
编译并且配置FPGA设备。

Can you switch the LED on an off with the switch? If yes, you have now inputs available. 
你能够通过开关来使得LED开关么?如果可以,那么你已经让输入信号工作起来了。

If not, you need to debug your FPGA configuration. 
The pin assignment can also be done with the GUI version of the tool.
如果不行,那么你需要调试你的FPGA配置。
管脚的赋值,也可以通过GUI版本的工具在完成。

Now use two switches and implement one of the basic combinational functions, e.g.,
AND two switches and show the result on the LED. Change the function. 
现在使用两个开关,并且实现一个基本的组合功能,例如对两个开关按钮信号做逻辑与运算,
并且把结果显式在LED上。然后改变函数的功能再试试效果。

The next step involves three input switches to implement a multiplexer: 
one acts as a select signal, and the other two are the two inputs for the 2:1 multiplexer.
下面的步骤涉及到了3个开关输入,以便实现一个多路器:
一个作为选择信号,另外两个开关输入信号作为多路器的两个输入信号,实现一个2选1的多路器。

Now you have been able to implement simple combinational functions 
and test them in real hardware in an FPGA. 
现在你已经能够实现一个简单的组合功能,并且再真正的硬件FPGA上测试它们。

As a next step, we will take a first look at how the build process works to generate an FPGA configuration. 
下一章,我们将会看一下编译器时怎么样生成了FPGA的配置文件的。

Furthermore, we will also explore a simple testing framework from Chisel, 
which allows you to test circuits without configuring an FPGA and toggle switches.
而且我们将会探索一个简单的Chisel测试框架,它允许你在没有去配置一个FPGA板子和闸刀开关的情况下去测试一个电路。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值