当前位置:网站首页>Chisel tutorial - 01 Introduction to Scala

Chisel tutorial - 01 Introduction to Scala

2022-07-07 23:41:00 github-3rr0r

Scala Introduce

What is? Scala

Scala It is a programming language that supports general programming paradigm , choice Scala The reasons for being a hardware development language are as follows :

  1. It is hosted embedded DSL A good language ;
  2. It has a powerful and elegant Library , Used to process various data sets ;
  3. There is a strict type system , Help early in the development cycle ( namely , Compile time ) Catch a large class of errors ;
  4. A way with powerful expression and transmission functions ;
  5. Chisel Than ChipelChijel and Chicel More palatable .( Here is a stem ,Chisel The whole journey is Constructing Hardware in a Scala Embedded Language, Here is the Scala Replaced with other languages , Such as Python,Java,C etc. , The abbreviation also changed )

In the discussion Chisel These points will become obvious when , But first of all, understand Scala Basic code reading and writing .

Variables and constants ——var and val

The statement to create a variable uses var(variable) Key words as a starting point , For constant creation val(value) key word .

Variables are variable , Constant is constant , Use constants whenever possible , Reduce errors and difficulties in reading caused by reusing variables .

Example :

var numberOfKittens = 6
val kittensPerHouse = 101
val alphabet = "abcdefghijklmnopqrstuvwxyz"
var done = false

Be careful :

  1. There is no need to add a semicolon after the statement ;
  2. Scala Will infer semicolons when line breaks ( It is also true when a single statement is distributed on multiple lines );
  3. Semicolons are only needed when multiple statements are placed on a line ;

var Can be reassigned , however val Once created, it is immutable , for example :

numberOfKittens += 1

// kittensPerHouse = kittensPerHouse * 2 //  This sentence cannot be compiled 

println(alphabet)
done = true

Conditional statements

Scala The implementation of conditional statements is similar to other languages :

//  A simple conditional statement 
if (numberOfKittens > kittensPerHouse) {
     
    println("Too many kittens!!!") 
}
//  You can omit braces when all branches have only one statement 
//  but Scala Style Guide Suggestions only exist else The curly braces are omitted when the statement 
// ( Although it can be compiled, it is not recommended )
if (numberOfKittens > kittensPerHouse) 
    println("Too many kittens!!!")

//  Here you can omit 
if (done) 
    println("we are done")
else 
    numberOfKittens += 1

//  There are branches with multiple lines of statements , Therefore, braces cannot be omitted  
if (done) {
    
    println("we are done")
}
else if (numberOfKittens < kittensPerHouse) {
    
    println("more kittens!")
    numberOfKittens += 1
}
else {
    
    done = true
}

But be careful ,Scala Inside if Statement will return a value , This value is determined by the last statement of the selected branch , This is useful for initializing functions and values within classes . such as :

val likelyCharactersSet = if (alphabet.length == 26)
    "english"
else 
    "not english"

println(likelyCharactersSet)

Here we create a constant likelyCharactersSet, But its value is given according to the condition at run time .

Method ( function )

Methods by def Keyword definition , In official documents abuse This notation is a function .

The parameters of the function are specified by a comma separated list , Include parameter name , Parameter type , Optional is the default value of the parameter .

It should be noted that , The type of return value needs to be given .

Without parameters Scala Functions do not need empty parentheses , In this way, it will be much easier to write code when class members become functions , Because some calculations are related by referencing it . By convention , Side effect free function without parameters ( Nothing will change except the return value ) Don't use parentheses , Functions with side effects ( You may change class variables or print content ) There should be brackets .

A simple statement

//  A simple scaling function , Multiply the input by 2, Such as times2(3) Returns the 6
//  Only one line of functions can omit braces 
def times2(x: Int): Int = 2 * x

//  A more complex function 
def distance(x: Int, y: Int, returnPositive: Boolean): Int = {
    
    val xy = x * y
    if (returnPositive) xy.abs else -xy.abs
}

function overloading

The same function name can be used multiple times .

The parameter list and type of the function determine the signature of the function , Let the compiler decide which function should be called .

//  Overloaded functions 
def times2(x: Int): Int = 2 * x
def times2(x: String): Int = 2 * x.toInt

times2(5)
times2("7")

Recursive and nested functions

Braces define the scope of the code .

There may be other functions or recursive function calls within the scope of a function . Functions defined within a specific scope are only available within that scope .

//  Print inverted triangle x array 
def asciiTriangle(rows: Int) {
    
    
    //  The multiplication of strings can copy strings many times 
    def printRow(columns: Int): Unit = println("X" * columns)
    
    if(rows > 0) {
    
        printRow(rows)
        asciiTriangle(rows - 1) //  Here is a recursive call 
    }
}

// printRow(1) //  The function call is not in scope , Compile not pass 
asciiTriangle(6)

list

Scala Implements various aggregated or sequential objects .

Lists are similar to arrays , But it supports additional (appending) And extraction (extracting) operation .

val x = 7
val y = 14
val list1 = List(1, 2, 3)
val list2 = x :: y :: y :: Nil       //  Another representation of a list 

val list3 = list1 ++ list2           //  Append the second list to the first list 
val m = list2.length
val s = list2.size

val headOfList = list1.head          //  Get the first element of the list 
val restOfList = list1.tail          //  Get the list with the first element removed from the list 

val third = list1(2)                 //  Get the third element of the list , from 0 Start index 

for sentence

Scala Yes for sentence , And traditional for Statements like , Values can be iterated over a range .

for (i <- 0 to 7) {
     print(i + "") }
println()

If you use until Replace to, Then it will start from 0 Iterate to 6, I.e. not included 7.

for (i <- 0 until 7) {
     print(i + "") }
println()

by You can specify a fixed increment , For example, this can output 0-10 Between all the integers :

for(i <- 0 to 10 by 2) {
     print(i + " ") }
println()

If a collection wants to access all its elements , have access to for As iterators , and Java as well as Python It's the same inside .

Here we create a list of four random number elements , Then I add :

//  This random number generation is not very elegant 
val randomList = List(scala.util.Random.nextInt(), scala.util.Random.nextInt(), scala.util.Random.nextInt(), scala.util.Random.nextInt())
var listSum = 0
for (value <- randomList) {
    
  listSum += value
}
println("sum is " + listSum)

for useful , But not the most convenient .

For example, sum the array elements , By calling comprehensions It is more convenient to calculate by the function family of .

The later part will also talk more about for And its kind .

read Scala Code

Call it efficient Chisel The designer , should :

  1. Able to read Scala Code ;
  2. Understand common naming conventions ;
  3. Understand common design patterns ;
  4. Understand common best practices ;

Chisel One of the charms of is code reuse , If you don't understand others' code, it's difficult to reuse .

It's also easier to ask for help by parsing other people's code effectively , For example, when searching online, you know how to search , How to ask questions on the Forum .

Let's start with common code patterns .

Package and import

package mytools
class Tool1 {
     ... }

When you need to reference a file that defines the above code , It should be :

import mytools.Tool1

Be careful : The name of the package needs to match the path level . It's not mandatory , But if you don't comply, you may have some difficulties in positioning bug.

By convention , The package name is lowercase , And does not contain delimiters such as underscores . It's not easy to get a good descriptive package name , The way is to add levels , such as package good.tools. Try to ,Chisel They will also do things that do not comply with this specification .

above ,import Statement tells the compiler that you want to use some additional libraries ,Chisel The import commonly used in programming is as follows :

import chisel3._
import chisel3.iotesters.{
    ChiselFlatSpec, Driver, PeekPokeTester}

The first sentence will put chisel3 All classes and methods inside are imported ,_ Represents a wildcard .

The second sentence starts from chisel3.iotesters The specified class is imported in .

Scala It's an object-oriented language

Scala It's object-oriented , So a little understanding can help maximize Scala and Chisel The advantages of .

There are many descriptions about object-oriented , Here are some official documents :

  1. Variables are objects ;
  2. adopt val The constants defined are objects ;
  3. Face value ( Fixed value ) Itself is the object ;
  4. Functions are also objects ;
  5. Object is an instance of a class ;
  6. in fact , stay Scala Almost everything important in , Objects in object-oriented are called instances ;
  7. When defining a class , The programmer specifies ;
  8. data (val and var) Associated with classes ;
  9. The operations that an instance of a class can perform , Called a method or function ;
  10. Class can be extended to other classes ;
  11. The extended class is a superclass , Extension objects are subclasses ;
  12. Subclasses inherit data and methods from superclasses ;
  13. There are some ways for classes to extend or override inherited properties ;
  14. Classes can be characterized (traits) Inherit ,Traits It can be understood as a lightweight class , It is allowed to inherit specific from multiple superclasses 、 Limited ways ;
  15. Single case (Singleton) Object is only a special Scala class ;
  16. They are not the above objects , We call them examples .

Now let's have a look at Scala How to define a class in .

An example of a class

stay Scala Creating a class in can be like this :

// WrapCounter Count to the maximum value determined according to the bit size 
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")
}

Include :

  1. class WrapCounterWrapCounter The definition of ;
  2. (counterBits: Int): Creating this object requires an integer parameter , By naming, you can prompt the meaning of parameters ;
  3. Braces delimit the code block , Most classes use a code block to define variables 、 Constants and methods ( function );
  4. val max: Long =: This class contains a member variable max, Declare as Long type , It is initialized when the class is created ;
  5. (1 << counterBits) - 1 Calculation counterBits The maximum value that bits can store , because max Is created as val The type will not change ;
  6. Variable counter Is created and initialized to 0L,L Express 0 It's a Long Type value , therefore counter To be inferred as Long type ;
  7. max and counter Are called class member variables ;
  8. Class method inc Defined as not accepting any parameters and returning Long The method of value ;
  9. inc The function body of the method includes :
    1. counter = counter + 1 perform counter Self increasing of 1 operation ;
    2. if (counter > max) { counter = 0 } test counter Is it greater than max Value , If established, it will counter Set as 0;
    3. counter: This last line is very important , The value of the expression in the last line of the code block is considered to be the return value of the code block , This return value can be used or ignored , This usage is very common , such as val result = if (10 * 10 > 90) "greater" else "lesser" It creates a val, Its value is "greater"
    4. So in this case , function inc Returns the counter Value ;
  10. println(s"counter created with max value $max"): Print string to standard output . because println Is defined directly in the code block , Is part of the class initialization code , Will be performed , That is, the output string , Every time an instance of this class creates a value, it executes ;
  11. The printed string in this example is an interpolation (interpolated) character string :
    1. Before double quotation marks s Represents an interpolation string ;
    2. Interpolation strings are processed at run time ;
    3. $max Will be max Value substitution ;
    4. If $ Followed by code blocks , Any of the Scala Statements can be contained in code blocks :
      1. such as println(s"doubled max is ${max + max}");
      2. The return value of the code block will be inserted to replace ${...};
      3. If the return value is not a string , That will be converted to a string ,scala Almost every class or type in has a defined conversion to string ;
    5. Generally, you need to avoid printing things every time you create an instance to prevent a lot of annotation output , Unless you are debugging ;

Create an instance of a class

Scala The instance uses built-in keywords new To create :

val x = new WrapCounter(2)

Many don't use new Keywords , such as val y = WrapCounter(6), This situation requires special attention , But it needs the use of accompanying objects , It will be mentioned in detail later .

The use examples of examples are as follows :

x.inc() // counter Self increasing 

//  example x Member variables of are externally visible , Unless declared private
if(x.counter == x.max) {
                  
    println("counter is about to wrap")
}

x inc() // Scala It is allowed not to use points , This helps make embedded DSL It looks more natural 

Code block

Code blocks are delimited by braces , A code block can contain 0 One or more lines of code , The last line will return the value .

A code block without code will return a similar null The object of , be called Unit.

Scala Code blocks are scattered throughout , For example, the body of a class definition , Definition of function method ,if The definition of the statement ,for The main body of .

Parameterized code block

Code blocks can receive parameters .

In the definition of classes and methods , These parameters look like other traditional programming languages .

In the following example ,c and s Is the parameter of the code block :

//  Only one line of code block does not need braces 
def add1(c: Int): Int = c + 1

class RepeatString(s: String) {
    
  val repeatedString = s + s
}

Be careful ! There are other ways to parameterize code blocks , such as :

val intList = List(1, 2, 3)
val stringList = intList.map {
     i =>
  i.toString
}

The code block is passed to List Methods in class map, This method requires its code block to have a single parameter . Call the code block for each member of the list , The code block returns the members converted to strings . This way of writing is anonymous function , stay Scala Various variants are available in . More details will be given later .

Here is to help you know all kinds of symbols when you encounter them . Here is the style that the official documents tend to , Other styles may be more natural under certain circumstances . Single line code style tends to be more concise , Complex blocks usually have narrative performance .

For easier collaboration , Recommend Scala Style Guide.

Named parameters and default parameter values

Take a look at the following method definitions :

def myMethod(count: Int, wrap: Boolean, wrapValue: Int = 24): Unit = {
     ... }

When this method is called , You will usually see that the parameter name corresponding to the incoming value is given :

myMethod(count = 10, wrap = false, wrapValue = 23)

Using named parameters , You can even call functions in different parameter order :

myMethod(wrapValue = 23, wrap = false, count = 10)

For frequently called methods , The order of parameters may be obvious , But for less common methods , Especially Boolean parameters , Including named parameters makes the code more readable . If a method has many parameters of the same type , Using named parameters can also reduce misuse .

The class definition can also use this construction method of named parameters .

When a specific parameter has a default value ( Do not need to be covered ) When , The caller just needs to ( By name ) Pass parameters without default values . such as wrapValue The default value is 24, therefore :

myMethod(wrap = false, count = 10)

According to 24 Was passed into the same calling function .

原网站

版权声明
本文为[github-3rr0r]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202130555354452.html