缘起
由于Gemmini
中使用的是Chisel
语言,故简单学习一下。
参考教程为:《Chisel Bootcamp》教程
网址如下:《Chisel Bootcamp》教程网址
正文
本篇文章主要围绕《第一章,scala
基本语法》进行学习。
说是学习Chisel
呢,怎么学scala
呢?因为Chisel
准确来说是用的scala
的语法。
说的专业一点,就是scala
是一门通用语言,可用于各个领域编程。而Chisel
是使用scala
实现的领域专用语言。
1.1 定义常量和变量
- 变量:
var
- 常量:
val
例如:
var numberOfKittens = 6
val kittensPerHouse = 101
val alphabet = "abcdefghijklmnopqrstuvwxyz"
var done = false
观察这个,可知道:
- 只区分常量还是变量,不像 C 语言那样区分那么多变量类型
- 不用分号结束,只用换行
1.2 条件判断-IF语句
if
语句
1、如果只有这样的一个 if
语句时(没有 else if),要加上 {}
。
// 正确做法:
if (numberOfKittens > kittensPerHouse) {
println("Too many kittens!!!")
}
//错误做法:
if (numberOfKittens > kittensPerHouse)
println("Too many kittens!!!")
2、如果 if 和 else 搭配时,并且内容为单行。
可以都不加 {}
。
if (done)
println("we are done")
else
numberOfKittens += 1
3、但是只要有一个分支中,超过一行了,那么每个分支都要加 {}
。
if (done) {
println("we are done")
}
else if (numberOfKittens < kittensPerHouse) {
println("more kittens!")
numberOfKittens += 1
}
else {
done = true
}
4、if 是可以返回值的!
val likelyCharactersSet = if (alphabet.length == 26)
"english"
else
"not english"
println(likelyCharactersSet)
这里,if 相当于函数,他会返回对应情况的值。
1.3 函数
1、一个简单的声明
def times2(x: Int): Int = 2 * x
def distance(x: Int, y: Int, returnPositive: Boolean): Int = {
val xy = x * y
if (returnPositive) xy.abs else -xy.abs
}
函数的注意事项:
- 声明函数用关键字
def
- 用
,
区分函数的变量,用:
描述变量所对应的变量类型 - 变量类型首写字母一般都大写
- 返回类型应该着重标出来,如
Int ={}
。 - 返回类型的前面应该要有一个
:
。这个意思,跟先指定变量,在跟着冒号加对应的变量类型一样。
2、重载函数
支持一个函数名,定义不同的函数体。但是不推荐这样做。
3、递归和嵌套函数
def asciiTriangle(rows: Int) {
def printRow(columns: Int): Unit = println("X" * columns)
if(rows > 0) {
printRow(rows)
asciiTriangle(rows - 1) // Here is the recursive call
}
}
// printRow(1) //这个函数不会表达
asciiTriangle(6)
{}
指明了函数的作用域,在这里面定义的函数,作用域外是不能表达的。
1.4 链表
构建链表的例子:
val x = 7
val y = 14
val list1 = List(1, 2, 3)
val list2 = x :: y :: y :: Nil // An alternate notation for assembling a list
val list3 = list1 ++ list2 // Appends the second list to the first list
val m = list2.length
val s = list2.size
val headOfList = list1.head // Gets the first element of the list
val restOfList = list1.tail // Get a new list with first element removed
val third = list1(2) // Gets the third element of a list (0-indexed)
1、构建链表有两种方法:
val list1 = List(1,2,3)
。直接用List()
val list2 = x::y::y::Nil
。::
这个表示右结合的操作符,表示将元素添加到链表的头部;Nil
是个空链表。执行的时候,先从空链表开始,从右往左加,依次是"空链表、y、y、x"。所以呈现出来的就是"x, y, y"
2、列表的简单使用- 两个列表相加:
list1 ++ list2
- 获取链表的长度:
list1.length
- 获取链表的尺寸:
list1.size
- 获取链表的第一个元素:
list1.head
- 获取链表中出第一个元素外剩下的所有元素:
list1.tail
- 根据下标找元素:
list1(2)
上面例子的运行结果:
x: Int = 7
y: Int = 14
list1: List[Int] = List(1, 2, 3)
list2: List[Int] = List(7, 14, 14)
list3: List[Int] = List(1, 2, 3, 7, 14, 14)
m: Int = 3
s: Int = 3
headOfList: Int = 1
restOfList: List[Int] = List(2, 3)
third: Int = 3
1.5 FOR语句
有四个小符号:<-
、to
、until
和 by
<-
:是将右面的内容依次给到左面。to
:相当于是集合中的]
,包括最后一个数until
:相当于是集合中的)
,不包括最后一个数by
:相当于条件,一般就是右边怎么样的给左面
示例如下:
代码:for (i <- 0 to 7) { print(i + " ") }
输出:0 1 2 3 4 5 6 7
代码:for (i <- 0 until 7) { print(i + " ") }
输出:0 1 2 3 4 5 6
代码:for(i <- 0 to 10 by 2) { print(i + " ") }
输出:0 2 4 6 8 10
遍历链表:
//val randomList = List(scala.util.Random.nextInt(), scala.util.Random.nextInt(), scala.util.Random.nextInt(), scala.util.Random.nextInt())
val randomList = List(1,2,3,4)
var listSum = 0
for (value <- randomList) {
listSum += value
}
println("sum is " + listSum)
- 直接把链表名放这里就行
value <- randomList
- 可以直接字符串加数字:
println("sum is " + listSum)
1.6 包和导入
定义包 (packages) 的方式
package mytools
class Tool1 { ... }
在其他地方引用的时候:
import mytools.Tool1
需要注意:
1、包名应该与文件的目录层次结构一致。例如:
- 如果包名是
mytools
,代码文件应该放在mytools
目录下。 - 如果包名是
good.tools
,代码文件应该在good/tools
目录下。
2、包名通常为小写、并且不应包含分隔符(如下划线_
)。
3、引用的细节处理
//引用包中的所有类和方法:
import chisel3._
//引用包中特定的类:
import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}
1.7 类
scala
是一个面向对象的语言。
类的示例;
class WrapCounter(counterBits: Int) {
val max: Long = (1 << counterBits) - 1
var counter = 0L
def inc(): Long = {
counter = counter + 1
if (counter > max) {
counter = 0
}
counter
}
println(s"counter created with max value $max")
}
(1 << counterBits) - 1
相当于 2 counterBits -1。<<
是移位符,左移位。println(s"counter created with max value $max")
这里,s
与$max
配对,$max
会被max
变量的值替换,如果没有s
就不会替换了。
1.8 类的实例
val x = new WrapCounter(2)
x.inc()
x inc()
if(x.counter == x.max) {
println("counter is about to wrap")
}
- 类一般可以通过
new
这个关键字来创建 - 使用类的变量可以有两种方式,一个是最普通的
.
,另一种是可以直接省略这个点,用空格代替。
1.9 代码块
在 {}
之内的就叫做代码块,最后一行是函数值(当然,也可以没有返回值)
如果没有返回值的话,就返回一个类似 null
的对象,在这里叫做 Unit
。
就像 if
语句一样,只有一行可以省略 {}
。
代码块也能接受参数, 例子中的 c 和 s,都是参数。
例子:
def add1(c: Int): Int = c + 1
class RepeatString(s: String) {
val repeatedString = s + s
}
代码块参数化:
例子:
val intList = List(1, 2, 3)
val stringList = intList.map { i =>
i.toString
}
- 调用了 List 类中的 map 方法。map 会遍历链表中的每一个元素。
i=>i.toString
是匿名函数。定义了一个接受参数 i,并返回 i.toString 的函数。=>
左面是参数,右面是函数体。这里表示将输入参数i
转换为字符串。
1.10 命名参数和默认参数值
实例代码,代码不完整:
//define a function
def myMethod(count: Int, wrap: Boolean, wrapValue: Int = 24): Unit = { ... }
//calling the function, named parameters
myMethod(count = 10, wrap = false, wrapValue = 23
//calling the function, parameter defaults
myMethod(wrap = false, count = 10)
所谓命名参数,就是调用函数时,将这些值都写出来,这样即使顺序不一致也没关系。
也有默认的参数值,在调用的的时候,不写的话,就会采取默认的值,例如这里的 wrapValue: Int = 24
, 如果,你调用的时候不写的话,就默认是一开始定义的 24
。
总结
本文主要学习了简单的scala
语法。刚刚接触,理解尚不深刻。如果有理解不准确的地方,欢迎大家评论区指正,一起交流学习!