Digital Design with Chisel Martin Schoeberl December 27, 2017 Abstract This lecture notes (to become a book) are an introduction into hardware design with the focus on using the hardware construction language Chisel. The approach of this book is to present small to medium sized typical hardware components to explore hardware design with Chisel. We will walk through these examples in detail.

1

Introduction

This book is an introduction to digital system design using a modern hardware construction language, Chisel [1]. In this book we focus on a slightly higher abstraction level to get you up to speed to build more complex, interacting digital systems. This book is not a general introduction to digital design and the fundamentals of it. For an introduction of basics, such as how to build a gate out of CMOS transistors refer to other digital design books. Hardware is now commonly described with a hardware description language (HDL). The time of drawing hardware components, even with CAD tools, is definitely over. Some high level schematics can give an overview of the system, but are not intended to describe the system. The two most common HDLs are Verilog and VHDL. Both languages are old, care a lot of legacy, and have a moving line of what constructions of the language are synthesizable to hardware. Do not get me wrong: VHDL and Verilog are perfectly able to describe hardware blocks that can be synthesized in an ASIC. For hardware design in Chisel, Verilog serves as an intermediate language for testing and synthesis.

1.1

Getting Started with the Tools

Chisel is a Scala library and the easiest way to install Chisel and Scala is with sbt, the Scala build tool. TODO: Describe sbt installation – or at least have pointer to it. TODO: Mention Quartus and Xilinx Vivado as FPGA tools.

1.2

Hello World

Each book on a programming language shall start with a minimal example, called the Hello World example. Following code is a first approach: object Hello { def main(args: Array[ String ]): Unit = {

println ("Hello World!") } }

Compiling and executing this short program with sbt sbt " runMain Hello"

leads to the expected output of a Hello World program: [info] Running Hello Hello World!

However, is this Chisel? Is this hardware generated to print a string? No, this is actually plain Scala code and not a representative Hello World program for a hardware design.

1.3

Chisel Testing Hello World

TODO: Show the testing printout like on the GitHub page of Chisel

1.4

Hardware Hello World

What is then the equivalent of a Hello World program for a hardware design? The minimal useful and visible design? A blinking LED is the hardware (or even embedded software) version of Hello World. If a LED blinks, we are ready to solve bigger problems! Following code shows a blinking LED, described in Chisel: class Hello extends Module { val io = new Bundle { val led = UInt(OUTPUT , 1) } val CNT_MAX = UInt (50000000 / 2 - 1); val cntReg = Reg(init = UInt (0, 32)) val blkReg = Reg(init = UInt (0, 1)) cntReg := cntReg + 1.U when( cntReg === CNT_MAX ) { cntReg := 0.U blkReg := ˜ blkReg } io.led := blkReg }

It is not important that you understand the details of this code example. We will cover those in the following chapters. Just note that the circuit is usually clocked with a high frequency, e.g., 50 MHz, and we need a counter to derive timing in the Hz range to achieve a visible blinking. In the above example we count from 0 up to 25000000-1 and then toggle the blinking signal (blkReg := ˜blkReg) and restart the counter (cntReg := 0.U). TODO: The above code is Chisel 3 in Chisel 2 compatibility mode. Switch to the real Chisel 3 code. 2

1.5

Source Access

This book is open source and hosted at GitHub: chisel-book. Small Chisel code snippets are included in the repository of the book. Larger examples are collected in the accompanying repository chisel-examples.

1.6

Exercises

Each chapter ends with a few hands-on exercises. For the introduction exercise we will use an FPGA board to get one LED blinking. As a first step clone (or first fork on GitHub) the chisel-examples repository. The Hello World example is in its own folder hello-world, setup as a minimal project. You can explore the Chisel code of the blinking LED in Hello.scala. Compile the blinking LED with following steps: git clone https:// github .com/ schoeberl /chisel - examples .git cd chisel - examples /hello -world/ make

After some initial downloading of Chisel components, this will produce the Verilog file Hello.v. Explore this Verilog file. You will see that it contains two inputs clock and reset and one output io led. When you compare this Verilog file with the Chisel module you will notice that the Chisel module does not contain clock or reset. Those signals are implicit generated and in most designs is convenient to not need to deal with these low-level details. Chisel provides register components and those are connected automatically to clock and reset (if needed). We also provide an additional Verilog top level in verilog/hello top.v, which can be used to avoid connecting a reset signal (as FPGA registers usually are set to 0 on FPGA configuration). The next step is to setup an FPGA project file for the synthesize tool, assign the pins, and compile1 the Verilog code, and configure the FPGA with the bitfile. We cannot provide the details on this steps. Please consult the manual of your Intel Quartus or Xilinx Vivado tool. However, the examples repository contains some ready to use Quartus projects in folder quartus for several popular FPGA boards (e.g., DE2-115). If it happens that your board is supported, start Quartus open the project, compile it by pressing the Play button, and configure the FPGA board with the Programmer button and one of the LEDs should blink. Gratulation! You managed to get your first design in Chisel running in an FPGA! Now change the blinking frequency to a slower or a faster value and rerun the build process. Blinking frequencies and also blinking patterns communicate different “emotions”. E.g., a slow blinking LED signals that everything is ok, a fast blinking LED signals an alarm state. Explore which frequencies signal best those two different emotions. As a more challenging extension to the exercise, generate a blinking pattern: the LED shall be on for 200 ms every second. For this pattern you might decouple the change of the LED blinking from the counter reset. You will need a second constant where you change the state of the blkReg register. What kind of emotion does this pattern produce? Is it alarming or more like a sign of live signal? 1 The real process is more elaborated with following steps: synthesizing the logic, performing place and route, performing timing analysis, and generating a bitfile. However, for the purpose of this introduction example we simply call it “compile” your code.

3

2

Basic Components

In this section we introduce the basic components for digital design. These basic elements can be combined to build larger, more interesting circuits. Here are two examples of basic components. A module containing combinational logic: import Chisel ._ class Logic extends Module { val io = new Bundle { val a = UInt(INPUT , 1) val b = UInt(INPUT , 1) val c = UInt(INPUT , 1) val out = UInt(OUTPUT , 1) } io.out := io.a & io.b | io.c }

An 8-bit register: import Chisel ._ class Register extends Module { val io = new Bundle { val in = UInt(INPUT , 8) val out = UInt(OUTPUT , 8) } val reg = Reg(init = UInt (0, 8)) reg := io.in io.out := reg }

2.1

Multiplexor

A multiplexor is a circuit that selects between alternatives. In the most basic form it selects between two alternatives. Figure 1 shows such a 2:1 multiplexer, or mux for short. Depending on the value of the select signal (sel) signal y will represent signal a or signale b.

2.2

Counting

Counting is a very basic 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 in digital design, counting starts at 0. Therefore, if we want to count till 10 we count from 0 to 9. The following code shows such a counter that counts till 9 and wraps around to 0 when reaching 9.

4

sel

a y b Figure 1: A basic 2:1 multiplexor. If we want to count N, we start with 0 and count till N-1. TODO: counter code This is straight forward. However, one might ask if this is the most efficient implementation of counting. The comparison agains an end value, 10 in our example, involves some combinational circuit in an ASIC. More efficient in an ASIC (and as well in loops of programs) is counting down and exit when 0 is reached. If we want to count N, we start with N-1 and count till 0. TODO: down counting code With a comparison against 0 we need only a NOR gat to detect the 0 condition. This optimization is valid for an ASIC, but not for an FPGA based on LUTs. With comparison using LUTs there is no difference comparing against a ’0’ or ’1’ bit. In that case use the better readable counting logic towards the end value. However, there is still one more trick a clever hardware designer can pull off. Counting up or down needed a comparison agains all counting bis, so far. What about counting down one to many? In that case the counter becomes negative. Detecting a negative value is simply comparing the most significant bit against ’a’. If we want to count N, we start with N-2 and count till -1. TODO: Show optimized down counting code. TODO: discuss ¿= and so on

3 3.1

Components FIFO Buffer

To decouple a write (sender) and a reader (receiver) some form of buffering between the writer and the reader is inserted. A common buffer is a first-in, first-out (FIFO) buffer. Figure 2 shows a writer, the FIFO, and a reader. Data is put into the FIFO by the writer on din with an active write signal. Data is read from the the FIFO by the reader on dout with an active read signal. A FIFO is initially empty, singled by the empty signal. Reading from an empty FIFO is usually undefined. When data is written and never read a FIFO will become full. Writing to a full FIFO is usually ignored and the data lost. In other words, the signals empty and full serve as handshake signals Several different implementations of a FIFO are possible: E.g., using on-chip memory and read and write pointers or simply a chain of registers with a tiny state machine.

5

write

Writer

full

read FIFO

empty

Reader

dout

din

Figure 2: A writer, a FIFO buffer, and a reader. For small buffers (up to tens of elements) a FIFO organized with individual registers connected into a chain of buffers is a simple and efficient implementation. We start by defining the IO signals for the writer and the reader. The size of the data is configurable with size. class val val val }

WriterIO (size: Int) extends Bundle { din = UInt(INPUT , size) write = Bool(INPUT) full = Bool( OUTPUT )

class val val val }

ReaderIO (size: Int) extends Bundle { dout = UInt(OUTPUT , size) read = Bool(INPUT) empty = Bool( OUTPUT )

4

Snippets

TODO: A collection is Chisel snippets collected along some coding A memory with sequential registered read and write ports: val mem = Mem(UInt(width = 8), 256, seqRead = true) val rdData = mem(Reg(next = rdAddr )) when( wrEna) { mem( wrAddr ) := wrData }

Initialize a Vec from a Scala array: val program = new Array[Bits ](3) program (0) = Bits (0x01 , 8) program (1) = Bits (0x23 , 8) program (2) = Bits (0x16 , 8) val rom = Vec( program )

State machine: val fetch :: execute :: load :: Nil = Enum(UInt (), 3)

6

val stateReg = Reg(init = fetch) switch ( stateReg ) { is( fetch) { stateReg := execute } is( execute ) { when( isLoad ) { stateReg := load }. otherwise { stateReg := fetch } } is(load) { stateReg := fetch } }

No default assignment possible when declaring a signal! Need an extra one.

4.1

SBT and Eclipse

Use an IDE, such as Eclipse, but generate the project with sbt from the library dependency description. E.g.,: TODO: add Eclipse stuff here.

5

Conclusion

Acknowledgment TODO: Sometimes we received some help. Sometimes external funding.

Source Access All code examples are available in open source from: https://github.com/schoeberl/chisel-examples

References [1] Jonathan Bachrach, Huy Vo, Brian Richards, Yunsup Lee, Andrew Waterman, Rimas Avizienis, John Wawrzynek, and Krste Asanovic. Chisel: constructing hardware in a Scala embedded language. In Patrick Groeneveld, Donatella Sciuto, and Soha Hassoun, editors, The 49th Annual Design Automation Conference (DAC 2012), pages 1216–1225, San Francisco, CA, USA, June 2012. ACM.

7

Digital Design with Chisel - GitHub

Dec 27, 2017 - This lecture notes (to become a book) are an introduction into hardware design with the focus on using the hardware construction language Chisel. The approach of this book is to present small to medium sized typical hardware components to explore hardware design with Chisel. We will walk through ...

95KB Sizes 0 Downloads 266 Views

Recommend Documents

Digital Signal Processing - GitHub
May 4, 2013 - The course provides a comprehensive overview of digital signal processing ... SCHOOL OF COMPUTER AND COMMUNICATION. SCIENCES.

[PDF BOOK] Digital Design with RTL Design, VHDL ...
Offering a modern updated approach to digital design this much needed book ... You are using an unsupported browser New user Create an account Sign in ...

Read eBOOK Digital Design with RTL Design, VHDL ...
Digital Logic Design Using Verilog Coding and RTL Synthesis Authors ... test and presented ways in which hardware description languages HDLs could be used ... for foreach in srv users serverpilot apps jujaitaly public index php on line 447.