【Gemmini】002-Chisel语言学习(一)

缘起

由于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语句

有四个小符号:<-tountilby

  • <-:是将右面的内容依次给到左面。
  • 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语法。刚刚接触,理解尚不深刻。如果有理解不准确的地方,欢迎大家评论区指正,一起交流学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值