Communicating State Machines
Martin Schoeberl
Technical University of Denmark Embedded Systems Engineering
March 31, 2022
Overview
I Input processing I Ready/valid interface I Display multiplexing I A little bit of Scala I Hardware generators
Exam Info
I I would like to hear about the exam
I ... nice if we could get the exams from earlier years...
I Old examsets to get a better understing of what the level is...
I Exam will be online
I All aids allowed, except Internet I PDF with exam questions I Upload solution in a single PDF
I Please use your study number as file name I Train to do a drawing and integrate it into a PDF
I Timing exercise, some coding, understanding questions, drawing circuits
I I uploaded an older exam at DTU Learn and solutions
A (Minimal) Project from Scratch
I How do we make a new project ourselves without editing the provided build.sbt files?
I Just two files: build.sbtand a.scalafile I Create the folder/directory structure I Copy abuild.sbt
I Import in InteliJ I Create a.scalaclass
I Show it now (in explorer or in terminal?) I Do this exercise today!
Group Workflow Suggestions
I Share code on GitHub (private repo)
I Meet in Zoom: you all have a full license from DTU I You can take over a screen to type
I You can draw on it
I Besides ad-hoc meetings, have a regular project meeting I Use Slack for quick notes and quick sharing of files I Maybe also try to share the.bitfile for the FPGA board I Use Google docs for taking notes, start your report I If you like Latex, use overleaf
I You can also work on the lab assignments at other times than the lab time ;-)
One Possible Solution for Last Lab
val MAX_CNT = 50000000. U // use a smaller value for waveform viewing
val tickCntReg = RegInit (0. U (32. W)) val cntReg = RegInit (0. U (4. W)) val tick = tickCntReg === MAX_CNT
tickCntReg := Mux ( tick , 0.U , tickCntReg + 1. U) when ( tick ) {
cntReg := cntReg + 1. U }
val m = Module (new SevenSegDec () ) m. io . in := cntReg
sevSeg := m. io . out
A Self-Running Tester
I SevenSegCountSpecis a self-running circuit I Has no input
I Needs no stimuli (poke) I Just run for a few cycles
class SevenSegCountSpec extends AnyFlatSpec with ChiselScalatestTester {
" SevenSegTest " should " pass " in { test (new CountSevenSeg )
. withAnnotations ( Seq ( WriteVcdAnnotation )) { dut =>
dut . clock . step (100) }
} }
Running the Test
I Does not really do any testing
I Just generated the waveform for debugging I Just running 100 cycles does not show much
I Increase the number of running cycles to 100000000?
I Or use a different constant for testing?
Today’s Lab
I Display multiplexer
I Input are 16 switches for 4 hexadecimal digits I Please show it a TA when finished for a “tick”
I There is a simulation available, show it
I Maybe extend it with binary to BCD conversion I This is optional/advanced material
I You can also start to work on the full Vending Machine I Top-level, pin definition, and a simple tester are in:
I https://github.com/schoeberl/chisel-lab/tree/
master/vending
I Update your copy. I have updated the description yesterday
Next Labs
I Next week: test a given Vending Machine
I The remaining weeks: work on the full Vending Machine
Input Processing
I Input signals are not synchronous to the clock I May violate setup and hold time of a flip-flop I Can lead to metastability
I Signals need to besynchronized I Using two flip-flops
I Metastability cannot be avoided I Assumption is:
I First flip-flop may become metastable I But will resolve within the clock period
Input Synchronizer
Synchronous circuit
External world
btn btnSync
val btnSync = RegNext ( RegNext ( btn ))
Bouncing Buttons
I Buttons and switches need some time to transition between on and off
I May bounce between the two values
I Without processing we detect more than one event I Solution is to filter out bouncing
I Can be done electrically (R + C + Schmitt trigger) I That is why you have the extra PCB with the buttons I But we can also do this digitally
I Assume bouncing timetbounce I Sample at a periodT >tbounce I Only use sampled signal
Sampling for Debouncing
bouncing in
debounced A
debounced B
Sampling for Debouncing
val FAC = 100000000/100
val btnDebReg = Reg ( Bool () ) val cntReg = RegInit (0. U (32. W)) val tick = cntReg === (fac -1) .U cntReg := cntReg + 1. U
when ( tick ) { cntReg := 0. U
btnDebReg := btnSync }
I We already know how to do this!
I Just generate timing with a counter
I We sample at 100 Hz (bouncing below 10 ms)
Communicating State Machines
I We did refactor a large FSM into smaller ones last week I FSMscommunicate
I Simple communication is:
I Input processing to the FSM I FSM with the datapath
I More complex FSMs may exchange data with handshaking
Handshaking
I Producer of data and consumer need to agree when data is transferred
I Producer tells when data is available/valid with avalid signal
I Consumer tells when it is ready toe receive data with a readysignal
I When both are asserted the transfer takes place I Also calledflow control
Ready-Valid Interface
valid
data ready
Receiver Sender
I Ready-valid flow control
Ready-Valid Interface, Early Ready
clock ready valid
data D
0 1 2 3 4 5 6
Ready-Valid Interface, Late Ready
clock ready valid
data D
0 1 2 3 4 5 6
Single Cycle and Back-to-Back
clock ready valid
data D1 D2 D3
0 1 2 3 4 5 6
Common Interface
I So common interface that Chisel defines aDecoupledIO class DecoupledIO[T <: Data ]( gen : T) extends
Bundle {
val ready = Input ( Bool () ) val valid = Output ( Bool () ) val bits = Output ( gen ) }
Display Multiplexing
I Saving of pins in the FPGA
I Switch between the four digits at around 1 kHz I Switchfasterin simulation
I Showschematics
I Also includes a display simulation for those without an FPGA
I Lab 9
I Sketch needed hardware on black board
First Summary and a Break
I Main topic of today done I Following is advanced material I A little bit of Scala
I How to write hardware generators
I Maybe extend your display to show decimal number I But first 10 minutes BREAK
I You wrote:More breaks. A lot of people lose focus after around 30 - 45 min.
Binary-Coded Decimal (BCD)
I Your current display shows numbers in hexadecimal I 1510is displayed as 0F16
I Which is in binary: 00001111
I We would like to see it as a ‘1’ followed by a ‘5’
I Which is in binary: 0001 0101
I Convert from binary to binary-coded decimal (BCD) I But only for the display
I Computing in BCD is hard
Binary to BCD Conversion Table
val bincode = io . sw (7 ,0)
val bcd = WireDefault ( bincode ) switch ( bincode ) {
is (0. U) { bcd := " b0000_0000 ".U } is (1. U) { bcd := " b0000_0001 ".U } is (2. U) { bcd := " b0000_0010 ".U } // ... some more
is (9. U) { bcd := " b0000_1001 ".U } is (10. U) { bcd := " b0001_0000 ".U } is (11. U) { bcd := " b0001_0001 ".U } is (12. U) { bcd := " b0001_0010 ".U } // ... and many more entries
}
Binary-Coded Decimal (BCD)
I Conversion is a table (= function) I Combinational logic
I Wecoulddo the table manually I But it is large
I The table has 100 entries to convert 0 to 99 to BCD I Let’s write a program for this
I We could use Java, Python, TCL,...
I We will write our firsthardware generator I First we need a little bit of Scala
Chisel and Scala
I Chisel is a library written in Scala
I Import the library withimport chisel3.
I Chisel code is Scala code
I When it is run isgenerateshardware I Verilog for synthesize
I Scala netlist for simulation (testing)
I Chisel is an embedded domain specific language I Two languages in one can be a little bit confusing
Scala
I Is object oriented I Is functional
I Strongly typed with very good type inference I Runs on the Java virtual machine
I Can call Java libraries I Consider it as Java++
I Can almost be written like Java I With a more lightweight syntax
Scala Hello World
object HelloScala extends App{ println (" Hello Chisel World !") }
I Compile withscalacand run withscala
I You can even use Scala as a scripting language I Or run withsbt run
I Show both
Scala Values and Variables
I Scala has two type of variables: vals andvars I Avalcannot be reassigned, it is a constant
I We use avalto name a hardware component in Chisel
// A value is a constant val zero = 0
// No new assignment is possible // The following will not compile zero = 3
I Types are usually inferred
I But can be explicitly stated as follows val number: Int = 42
Scala Variables
I Avarcan be reassigned, it is like a classic variable I We use avarto write a hardware generator in Chisel
// We can change the value of a var variable var x = 2
x = 3
Simple Loops
// Loops from 0 to 9
// Automatically creates loop value i for (i <- 0 until 10) {
println (i) }
I We use a loop to generate hardware components
Scala for Loop for Circuit Generation
val regVec = Reg ( Vec (8 , UInt (1. W))) regVec (0) := io . din
for (i <- 1 until 8) { regVec (i) := regVec (i -1) }
I foris Scala
I This loop generates several connections I The connections are parallel hardware I This is a shift register
Conditions
for (i <- 0 until 10) { if (i %2 == 0) {
println (i + " is even ") } else {
println (i + " is odd ") }
}
I Executed at runtime, when the circuit is created I This isnota mlutplexer
Scala Arrays and Lists
// An integer array with 10 elements val numbers = new Array [ Int ](10) for (i <- 0 until numbers . length ) {
numbers (i) = i *10 }
println ( numbers (9) )
// List of integers val list = List (1 , 2, 3) println ( list )
// Different form of list construction val listenum = ’a ’ :: ’b ’ :: ’c ’ :: Nil println ( listenum )
Scala Classes
// A simple class class Example {
// A field , initialized in the constructor var n = 0
// A setter method def set(v: Int ) = {
n = v }
// Another method def print() = {
println (n) }
}
Scala (Singleton) Object
object Example {}
I Forstaticfields and methods
I Scala has no static fields or methods like Java I Needed formain
I Useful for helper functions
Singleton Object for the main
// A singleton object object Example {
// The start of a Scala program
def main( args : Array [ String ]) : Unit = { val e = new Example ()
e. print () e. set (42) e. print () }
}
I Compile and run it with sbt (or within Eclipse/IntelliJ):
sbt " runMain Example "
Conditional Circuit Generation
class Base extends Module { val io = new Bundle () } class VariantA extends Base { }
class VariantB extends Base { }
val m = if ( useA ) Module (new VariantA () ) else Module (new VariantB () ) I ifandelseis Scala
I ifis an expression that returns a value I Like “cond ? a : b;” in C and Java I This is not a hardware multiplexer I Decides which module to generate
I Could even read an XML file for the configuration
A Table with a Chisel Vec
I A ChiselVecis a collection of signals or registers I Similar to an Array in other languages
I Vecin aWireis a combinational table (mulitplexer) I Vecin aRegis a collection of registers
I Create with number of elements and hardware type val v = Wire ( Vec (3 , UInt (4. W)))
A Combinational Vec
I A combinationalVecis basically a multiplexer I Input signal/wire connected with a constant index I Output select with a ChiselUIntsignal
v (0) := 1. U v (1) := 3. U v (2) := 5. U
val index = 1. U (2. W) val a = v( index )
I Also convenient to represent a larger table I Instead of aswitchtable
I Input can be with Scala code
Binary to BCD Conversion
import chisel3 ._
class BcdTable extends Module { val io = IO (new Bundle {
val address = Input ( UInt (8. W)) val data = Output ( UInt (8. W)) })
val table = Wire ( Vec (100 , UInt (8. W))) // Convert binary to BCD
for (i <- 0 until 100) {
table (i) := ((( i /10) < <4) + i %10) .U }
io . data := table ( io . address ) }
Today Lab
I Do a project from scratch I Display multiplexing
I Can also be developed in simulation
Summary
I External inputs need processing I Minimum is a input synchronizer
I Communicating circuits/FSMs need handshaking I Ready-valid interface
I Scala can be used to write circuitgenerators
I We explored generation of a binary to BCD conversion table