Jump to Navigation

Documentation

This documentation is a  out of date but currently is the best available. It is included as a placeholder, but the best description's are included in the examples.  

ScalaDL

ScalaDL is a code generator for hardware languages implemented  as an internal DSL inside Scala. The goal of this language is to contain syntax extremely close to verilog, with the power of an advanced software language for scripting, as well as adding more abstract descriptions for common operations like signal processing, state machines, and others.  A few examples are shown below.

Examples

A few examples of source code for this tool can be found on github with links below

Parallel FFT Example

 

Verilog Output Directory

Basic Syntax               

Verilog Output File

 

State Machine           

Verilog Output File  

Directory

IIR Example                 

Verilog Output File

 

Processor Interface 

Verilog Output File

Directory

FIR Example               

Verilog Output File

Directory

Status / Alpha Users

This tool is a combination of a refactoring of a previous  signal processing tool , with code used in the creation of the coherent optical cores as well as a brand new front end embedded in Scala. An alpha version is close to ready to be released. If you are interested in using this tool please contact support@simplifide.com.  This document is also at an alpha state but will be improved in parallel with the code.

Background

The current hardware design languages are very good at describing low level hardware functions. They are less good at higher level abstractions and paramerization. This is for the most part positive as it keeps engineers thinking about what the actual code maps to in terms of hardware.  The newer generation of  tools attempt to use higher level languages to abstract away from the hardware and allow the tools to create micro-architectures. These tools are good for certain designs but tend to break down for resource sharing in certain cases as well as suffer from difficulty in low level control design.

The correct approach to this problem is to allow a higher level description of designs without abstracting away  from what is being implemented and still allow the low level RTL to be used when necessary. Hardware designs entail many different diverse tasks which make the task of construction a high level language extremely difficult if not impossible.

ScalaDL is not a language but instead a code generator which is embedded in Scala using an internal DSL. This allows the full power of Scala for parameterization and abstraction while keeping the low level verilog style instructions, while also allowing standard signal processing notation as well as simple entry mechanisms for state machines and design hierarchies. Embedding a verilog style language inside Scala has numerous advantages beyond parameterization like allowing users easy customization over the process as well as advanced software tools for devleopment.

History

This project is the 6th completely new revision of a set of code generation tools which have been used to create over 10 commerical ASICs and numerous smaller cores. The generators were all built to solve the issue of automating the mundane and bug ridden task of creating hardware structures as well as creating truely parameterizable cores.. The issue with all of the previous versions related to combining operations better specified in an HDL like language with auto generated code.

 The last 2 solutions to thise problem involved embedding first python and then scala with an external DSL into the comments. The signal processing tool described in the link was a subset of this operation. The issue with this solution was embedding code into comments or even templates in the file is non-optimal and true parameterization was not easy. This latest version solves this issue by allowing Verilog like constructs inside the language.

Language

Scala's DSL feature is powerful but has a few limitations. Great effort has been made to make many of the features of the language similar to Verilog but there are small differences which are required. The language is also in development and small changes to the existing syntax as well as large additions are to be expected.

Project

TBD

Module

Modules are scala classes which override the scala class Module. The Module class can be written similar to a verilog module where statements are written directly into the class body. This is mainly done using functions defined in the module class, but also contains a bit of "magic" which is required  to give a more readable syntax. 

Signals

Signals are defined in a similar fashion to verilog and can be declared as Input, Output, Wire, Reg. They also by default contain a fixed point <s,n,k> definition of their size. In addition to signals there are arrays busses which can contain any type or list of signals. Complex signals are also supported. Most operations should support any group of signals and expand them out when creating the code.

Signal Declaration

Signal declaraions like in verilog can occur directly under the module class using some convenience functions. These operations create the variables and append them to the module class. A few examples are shown below. 

val sig      = signal("sig1",WIRE,S(8,6))          // Creates a signed wire of width 8 with 6 fractional bits

val com    = complex("com",REG,S(8,6))  //  Creates a complex register of width 8 with 6 fractional bits

val arr      = array("a",WIRE,U(8,6)(5)   // Creates an array of 5 unsiged wires

val reg      =register("a",WIRE,U(8,6)(5)(clk)   // Creates an array of 5 unsiged wires

The register syntax has a slightly different meaning which automatically creates a signal with 4 delayed signals as well as the flop.

Statements

Statements are similar to other programming languages including Verilog without the assign prefix. The operator used for assignment is either := or ::=.These operators were selected to not conflct with other operators to simplify the parser. All standard verilog operators are supported as well as a few convenience functions which are shown below. 

     // Simple & operation

      signal1      := signal2 & signal2    

      // Flop with Single Condition

     signal1   := signal1 @@ clk

     // Flop with multiple conditions and indexing an array

     signal1(0)   := (signal1(0) -> signal1(1)) @@ clk

      // Question Mark Statement

     signal1      := signal1 ? signal1 :: signal1

Operators and Signal Indexing

ScalaDL handles all standard verilog operators with a one to one correspondance. There is a bit of extra complexity associated with indexing signals as well as concatenations.

     // Signal Selection - The case below shows signal selection of an array

     signal1(0)(5,1)   := signal2(0)(5,1)

 

     // Sign extension - This shows the replacement for using the curly operators

     signal1   := cat (rep(signal2.top,4),signal2) // {{4{signal2[W]}},signal2}

 

     // Delay Selection - Signal1 is assigned the value of a delayed version of signal2

     signal1   := signal2(n-1)

 

Alway Blocks and Conditional Statements

Conditional statements as well as general control is extremely difficult to handle in a code generators. The syntax in ScalaDL is extremely close to Verilog syntax with some subtle differences due related to the functional nature of the operations. The main differences is the use of parenthesis and extra required semicolons.

     // General Condition Statement -- The Always Block is Optional

      $always_star(

        $if (condition1) (

          signal2 ::= signal1

        ),

        $else_if (condition2) (

          signal2 ::= signal1

        )

      )

 

      // Case Statement

      $always_star(

        $case(condition1) (

          condition1 -> (signal1 ::= signal2),

          condition2 -> (signal1 ::= signal2)

        )

      )

State Machine

State machines are extremely common in HDLs and for proper synthesis requires a much larger syntax to describe the operation.  The much compressed syntax shown below the operations in an easy method to see and debug. Because the model is enclosed in scala creating a diagram is trivial as well as verifying potential issues with the design.

  // State Machine Test

  val stateA = new State("a",0,List(signal1(0) ::= signal2(0)))

  val stateB = new State("b",1,List(signal1(1) ::= signal2(1)))

  val stateC = new State("c",2,List(signal1(2) ::= signal2(2)))

 

  val gr = StateModel((stateA -> stateB) ## (condition1 == condition2),

                      (stateB -> stateC) ## condition2,

                      (stateC -> stateA) ## condition2)

 

  state_machine(gr,clk,state,next)

Signal Processing

Signal processing is a very broad range of design, and for proper support requires numeros general hardware functions to be written to handle a lot of the functionallity. This language supports a general method for creating these functions as well as writing modules directly.

     // Simple Example - No Rounding/Clipping

 

     y(n) := x(n)    + a(0)*y(n-1) + a(1)*y(n-2)

     z(n) := b*y(n)  + b(1)*y(n-1) + b(2)*y(n-2)

 

The code above is a simple IIR filter without rounding to make the operation easier to read.

 

     // Round and clip the inputs multiplier outputs and the adder

 

     y(n) := RC(x(n)    + RC(a(0)*y(n-1),iW) + RC(a(1)*y(n-2),iW))

     z(n) := RC(RC(b*y(n),iW)  + RC(b(1)*y(n-1),iW) + RC(b(2)*y(n-2),iW))

 

The code above extends the case adding rouding and clipping. Admittedly this should be split up for easier reading.

 

// Generalize the filter to any length -- Kind of architecturally this design will have timing issues

     y(n) := x(n) + List.tabulate(len)(i => RC(a(i)*y(n-i))).reduceLeft[Expression](_+_)

     z(n) := List.tabulate(len)(i => RC(b(i)*y(n-i))).reduceLeft[Expression](_+_)

 

The code above is a generalization of the IIR structure to any number of taps. This isn't quite true as the delay would be an issue with a large number of taps, but the example shows the easy generalization. The syntax might seem cryptic to people not used to Scala or functional programming, but the operation is quite simple. Tabulate works like a for loop and reduceleft like an accumulation.

 

Resource Sharing

Resource sharing is currently not implemented but will most likely function similar to the last version of the signal processing tool, using index to specify the time index inside the clock. An example of this operation is shown below.

Xr[2k]    = Ar[2k]   * Br[2k];

Xr[2k+1]  = Ai[2k+1] * Bi[2k+1];

 

Processor Interfaces

TBD

Chip Hierarchy

TBD

The chip hierarchichal creation will be supported both using standard instantiations inside blocks as well as a specialized graph based syntax which will allow the hierarchy to be specified using a simple graph which is expanded automatically creating the leaf modules as well as the signal.



Main menu 2

by Dr. Radut.