• This repository has been archived on 02/Jul/2021
  • Stars
    star
    430
  • Rank 101,083 (Top 2 %)
  • Language
    C++
  • License
    Other
  • Created about 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Just-In-Time Compiler for Verilog from VMware Research

! VMware has ended active development of this project, this repository will no longer be updated. alt text

Build Status Coverage Status

FPGAs can exceed the performance of general-purpose CPUs by several orders of magnitude and offer dramatically lower cost and time to market than ASICs. While the benefits are substantial, programming an FPGA can be an extremely slow process. Trivial programs can take several minutes to compile using a traditional compiler, and complex designs can take hours or longer.

Cascade is a novel solution to this problem, the world's first just-in-time compiler for Verilog. Cascade executes code immediately in a software simulator, and performs compilation in the background. When compilation is finished, the code is moved into hardware, and from the user’s perspective it simply gets faster over time. Cascade's ability to move code back and forth between software and hardware also makes it the first platform to provide generic support for the execution of unsynthesizable Verilog from hardware. The effects are substantial. Cascade encourages more frequent compilation, reduces the time required for developers to produce working hardware designs, and transforms HDL development into something which closely resembes writing JavaScript or Python. It takes the first steps towards bridging the gap between programming software and programming hardware.

Much of the work which has gone into building Cascade has been documented in conference proceedings. A complete list of publications (hopefully with more to come) is below. Note however, that Cascade is under active development. In some cases, its implementation may have diverged what is described in these texts. The most up-to-date information on Cascade's implementation is always its source code.

Recent Updates:

  • 12/19 Cascade supports the ULX3S as a backend target.
  • 11/19 Cascade uses Verilator as an intermediate compilation pass between software simulation and hardware.
  • 10/19 Cascade provides experimental support for Xilinx FPGAs on Amazon F1 (release coming soon).
  • 9/19 Cascade can be linked into C++ projects as a library. This allows Cacade to target itself as a backend target.
  • 7/19 Cascade supports unsynthesizable file I/O primitives from hardware.
  • 5/19 Cascade supports the DE10 Nano as a backend target.

Index

  1. Dependencies
  2. Building Cascade
  3. Using Cascade
    1. Command Line Interface
    2. As a Library
  4. Environments
    1. Software Backend
    2. Hardware Backends
      1. DE10 Nano
      2. ULX3S
    3. JIT Compilation
  5. Support for Synthesizable Verilog
  6. Support for Unsynthesizable Verilog
  7. Standard Library
  8. Target-Specific Components
  9. Adding Support for New Backends
  10. FAQ

Dependencies

Cascade should build successfully on OSX and most Linux distributions.

Building Cascade

  1. Clone this repository
$ git clone https://github.com/vmware/cascade
  1. Run the setup script
$ cd cascade
$ ./setup

The setup script should guide you through installing dependencies, as well as configuring, building and testing Cascade.

Using Cascade

Command Line Interface

Start Cascade by typing

$ cascade

This will place you in a Read-Evaluate-Print-Loop (REPL). Code which is typed here is appended to the source of the (initially empty) top-level (root) module and evaluated immediately. Try defining a wire.

>>> wire x;

The Verilog specification requires that code inside of initial blocks is executed exactly once when a program begins executing. Because Cascade is a dynamic environment, we generalize that specification: code inside of initial blocks is executed exactly once immediately after it is compiled. Try printing the value of the wire you just defined. Cascade uses a two-value model for signals. Unknown logic values (X) are set to zero, and high-impedence values (Z) are assigned non-deterministic values.

>>> initial $display(x);
>>> 0

Now try printing a variable which hasn't been defined.

>>> initial $display(y);
>>> Typechecker Error:
>>>  > In final line of user input:
>>>    Referenece to unresolved identifier: y

Anything you enter into the REPL is lexed, parsed, type-checked, and compiled. If any part of this process fails, Cascade will produce an error message and the remainder of your text will be ignored. If you type multiple statements, anything which compiles successfully before the error is encountered cannot be undone. Below, x and y are declared successfully, but the redeclaration of x produces an error.

>>> wire x,y,x;
>>> Typechecker Error:
>>>  > In final line of user input:
>>>    A variable named x already appears in this scope.
>>>    Previous declaration appears in previous user input.
>>> initial $display(y);
>>> 0

You can declare and instantiate modules from the REPL as well. Note however, that declarations will be type-checked in the global scope. Variables which you may have declared in the root module will not be visible here. It isn't until a module is instantiated that it can access program state.

>>> module Foo(
>>>   input wire x,
>>>   output wire y 
>>> );
>>>   assign y = x;
>>> endmodule
>>> wire q,r;
>>> Foo f(q,r);

If you don't want to type your entire program into the REPL you can use the include statement, where path/ is assumed to be relative to your current working directory.

>>> `include "path/to/file.v"

If you'd like to use additional search paths, you can start Cascade using the -I flag and provide a list of semicolon-separated alternatives. Cascade will try each of these paths as a prefix, in order, until it finds a match.

$ cascade -I path/to/dir1:path/to/dir2

Alternately, you can start Cascade with the -e flag and the name of a file to include.

$ cascade -e path/to/file.v

Finally, Cascade will stop running whenever a program invokes the $finish task.

>>> initial $finish;
Goodbye!

You can also force a shutdown by typing Ctrl-C or Ctrl-D.

>>> module Foo(); wir... I give up... arg... ^C

As a Library

Cascade can also be called directly from C++ code. Cascade's command line interface is a thin-wrapper around a small set of functions. A minimal example is shown below. Further dicussion of the concepts in this example appears in subsequent sections of this README.

#include <cassert>
#include <iostream>
#include <sstream>
#include <cascade.h>

using namespace cascade;
using namespace std;

int main() {
    // Create an instance of Cascade. Cascade is thread-safe. Multiple instances
    // may share the same address space.
    Cascade cascade;
    
    // Configuration options. These methods should all be called before
    // cascade starts running.
    cascade.set_include_dirs(...);
    cascade.set_enable_inlining(...);
    cascade.set_open_loop_target(...);
    cascade.set_quartus_server(...);
    cascade.set_profile_interval(...);

    // Cascade exposes its six i/o streams (the standard STDIN, STDOUT, and
    // STDERR, along with  three additional STDWARN, STDINFO, STDLOG) as
    // C++ streambufs. These are initially mapped to nullptr. Changes to this
    // mapping should also be made before cascade starts running.
    cascade.set_stdin(cin.rdbuf());
    cascade.set_stdout(cout.rdbuf());
    cascade.set_stderr(cerr.rdbuf());
    cascade.set_stdwarn(cerr.rdbuf());
    cascade.set_stdinfo(clog.rdbuf());
    cascade.set_stdlog(...);
    
    // Start cascade. This method returns immediately.
    cascade.run();
    
    // Cascade will run until the user's program invokes the $finish() task or the 
    // user requests that it stop running. The request_stop() method returns immediately. 
    // The wait_for_stop() method will block until either of the above conditions
    // is satisified.
    cascade.request_stop();
    cascade.wait_for_stop();
    
    // Stopping cascade only pauses its execution. All previous state is retained.
    // To continue running, call run() again.
    cascade.run();
    
    // Cascade is a c++ ostream. While it is running, any text provided to it
    // via the << operator, will be eval'ed. Since every program must begin with an
    // march file, you can use an include statement to eval one.
    cascade << "`include \"path/to/march.v\"";
    
    // Because cascade runs asynchronously, it has no way of knowing when user input
    // has ended. The user can force this by using the flush() method, or passing 
    // cascade a c++ endl. Be careful with using endl to separate multi-line inputs.
    // This may cause cascade to prematurely evaluate user input. When in doubt, prefer '\n'.
    cascade.flush(); 
    cascade << endl;
    
    // The results of the eval statements which have taken place since the previous
    // flush are available through ostream status bits. Cascade is placed in
    // in the eof state when it encounters an eof character, and in the bad state when
    // an eval results in a parse or type error. Because cascade runs asynchronously, the 
    // only way to make sure an eval has run to completion is to request a stop. The standard
    // mechanism for clearing an ostream's state bits is to use the clear() method.
    
    assert(!cascade.bad()); // Not guaranteed to see the result of the previous eval.
    cascade.stop_now(); // Syntactic sugar for request_stop(); wait_for_stop();
    assert(!cascade.bad()); // Both guaranteed to see the result of the previous eval.
    assert(!cascade.eof()); 
    cascade.clear(); // Clears eof and bad bits.
    
    // While cascade is stopped, it is safe to replace its rdbuf. For example:
    stringstream ss("wire x; initial $display(\"Hello, world!\");");
    cascade.rdbuf(ss.rdbuf());
    cascade.run();
    
    // Note however, that most c++ implementations assign non-standard semantics to
    // cin. It's safe to switch cascade's rdbuf to cin. But once this is done, it is
    // no longer safe to change it again.
    cascade.stop_now();
    cascade.rdbuf(cin.rdbuf());
    cascade.rdbuf(ss.rdbuf()); // UNDEFINED!
    cascade.run();
    
    // Block until the user's program invokes the $finish() task.
    cascade.wait_for_stop();

    return 0;
}

To build a program that uses Cascade as a library, statically link against libcascade. If you installed cascade to a directory other than /usr/local/ you'll need to provide alternate values for the -I and -L flags.

$ g++ --std=c++17 -I/usr/local/include/cascade my_program.cc -lcascade

Environments

Software Backend

By default, Cascade runs in software. You can invoke this behavior explicitly using the --sw flag.

$ cascade --march sw

This environment declares the following module and instantiates it into the top-level module for you:

module Clock(
  output wire val
);
endmodule

Clock clock;

This module represents the global clock. Its value toggles between zero and one every cycle. Try typing the following (and remember that you can type Ctrl-C to quit):

>>> always @(clock.val) $display(clock.val);
>>> 0
>>> 1
>>> 0
>>> 1
>>> ...

This global clock can be used to implement sequential circuits, such as the barrel shifter shown below.

>>> module BShift(
>>>   input wire clk,
>>>   output reg[7:0] val
>>> );
>>>   always @(posedge clk) begin
>>>     val <= (val == 8'h80) ? 8'h01 : (val << 1);
>>>   end
>>> endmodule
>>> wire[7:0] x;
>>> BShift bs(clock.val, x);

Compared to a traditional compiler which assumes a fixed clock rate, Cascade's clock is virtual: the amount of time between ticks can vary from one cycle to the next, and is a function of both how large your program and is and how often and how much I/O it performs. This abstraction is the key mechanism by which Cascade is able to move programs between software and hardware without involving the user.

Up until this point the code we've looked at has been entirely compute-based. However most hardware programs involve the use of I/O peripherals. Before we get into real hardware, first try running Cascade's virtual software FPGA.

$ sw_fpga

Cascade's virtual FPGA provides an ncurses GUI with four buttons, one reset, and eight leds. You can toggle the buttons using the 1 2 3 4 keys, toggle the reset using the r key, and shut down the virtual FPGA by typing q. Cascade's software backend will automatically detect the virtual FPGA and expose its peripherals as modules which are implicitly declared and instantiated in the top-level module:

module Pad(
  output wire[3:0] val
);
endmodule
Pad pad();

module Reset(
  output wire val
);
endmodule
Reset reset();

module Led(
  output wire[7:0] val
);
endmodule
Led led();

Try writing a simple program that connects the pads to the leds.

>>> assign led.val = pad.val;

Toggling the pads should now change the values of the leds for as long as Cascade is running.

Hardware Backends

Cascade currently provides support for two hardware backends: the Terasic DE10 Nano SoC and the ULX3S. When Cascade is run on either of these targets, instead of mapping compute and leds onto virtual components, it can map them directly onto real hardware.

DE10 Nano

Before using the de10 backend you'll first need to install Intel's Quartus Lite IDE on a network-accessible 64-bit Linux machine. You'll also need to run Cascade's compilation server on that machine.

$ quartus_server --path <quartus/install/dir> --port 9900

Alternatively, you can use Quartus Lite IDE installed on a remote host:

$ quartus_server --tunnel-command <command/like/ssh> --path <quartus/install/dir> --port 9900

Next you'll need an SD card image for your DE10 with a valid installation of Cascade. Cascade can generate this image for you automatically or you can download a prebuilt image here (todo). Reboot your DE10 using this image and run Cascade as usual (but on the DE10, use sudo).

$ cd cascade
$ sudo cascade --march de10 --quartus_host <64-bit Linux IP> --quartus_port <64-bit Linux port>

Assuming Cascade is able to successfully connect to the FPGA fabric, you will be presented with a similar environment to the one you encountered when using the software backend. The only difference is that instead of a Reset module, Cascade will implicitly declare the following module, which represents the DE10's Arduino header.

module GPIO(
  input wire[7:0] val
);
endmodule
GPIO gpio();

Try repeating the example from the previous section and watch real buttons toggle real leds.

ULX3S

Cascade supports the ULX3S using the entirely open source Yosys->NextPNR->ujprog toolchain. Before getting started, you'll need to follow the directions here for installing Yosys and NextPNR, and here for installing ujprog. Make sure that all components are installed to the standard /usr/local directory tree.

Next, you should be able to run Cascade as usual.

$ cascade --march ulx3s

Cascade does not currently support any of the I/O peripherals on the ULX3s, but it can target its reprogrammable fabric to improve virtual clock frequency for most applications.

JIT Compilation

If you'd like more information on how Cascade transitions code between software and hardware, trying using the --enable_info flag. This will cause Cascade to print status updates to the REPL whenever part of your program begins execution in a new context.

$ cascade --enable_info

In general, you can expect your virtual clock frequency to increase as more and more of your logic transitions to hardware. Providing the --profile <n> flag will cause Cascade to periodically (every seconds) print the current time and Cascade's virtual clock frequency to the REPL. To see this effect, try executing a very long-running program.

$ cascade --march <sw|de10|ulx3s> -e share/cascade/test/benchmark/bitcoin/run_25.v --enable_info --profile 3

Support for Synthesizable Verilog

Cascade currently supports a large --- though certainly not complete --- subset of the Verilog 2005 Standard. The following partial list should give a good impression of what Cascade is capable of.

Feature Class Feature Supported In Progress Will Not Support
Compiler Directives `define x
`undef x
`ifdef x
`ifndef x
`elsif x
`else w x
`endif x
`include x
Primitive Types Net Declarations x
Reg Declarations x
Integer Declarations x
Real Declarations x
Time Declarations x
Realtime Declarations x
Array Declarations x
Expressions Arithmetic Operators x
Bitwise Operators x
Logical Operators x
Concatentation Operators x
Conditional Operators x
Bit/Part Select x
Strings x
Real Constants x
Parameters Parameter Declarations x
Localparam Declarations x
Defparam Statements x
Module Declarations Input Ports x
Output Ports x
Inout Ports x
Module Instantiations Named Parameter Binding x
Ordered Parameter Binding x
Named Port Binding x
Ordered Port Binding x
Instantiation Arrays x
Generate Constructs Genvar Declarations x
Case Generate Constructs x
If Generate Constructs x
Loop Generate Constructs x

Support for Unsynthesizable Verilog

Cascade provides support for many of the unsynthesizable system tasks which are described in the 2005 specification, along with a few others which are unique to a just-in-time enviornment. One of the things that makes Cascade so powerful is that it supports the execution of unsynthesizable systems tasks even when a program is running in hardware. With Cascade, there's no reason to shy away from the use of $display() as a debugging tool. Unsynthesizable system tasks are guaranteed to run correctly on every target.

A complete listing of the system tasks which Cascade supports, along with a brief description of their behavior is shown below.

Feature Class Feature Supported In Progress Will Not Support
Printf $display(fmt, args...) x
$write(fmt, args...) x
Scanf $scanf(fmt, args...) x
Debugging $monitor(var) x
$list(name) x
$showscopes(n) x
$showvars(vars...) x
Logging $info(fmt, args...) x
$warning(fmt, args...) x
$error(fmt, args...) x
Simulation Control $finish(code) x
$fatal(code, fmt, args...) x
Virtualization $save(file) x
$restart(file) x
$retarget(march) x
File I/O $fopen(path, mode) x
$fclose(fd) x
$fdisplay(fd, fmt, args...) x
$feof(fd) x
$fflush(fd) x
$fgetc(fd) x
$fgets(str, fd) x
$fread(fd, var) x
$fscanf(fd, fmt, args...) x
$fseek(fd, off, dir) x
$ftell(fd) x
$fwrite(fd, fmt, args...) x
$rewind(fd, off, dir) x
$ungetc(c, dir) x

Printf Tasks

The printf family of system tasks can be used to emit debugging statements to stdout (the REPL). Both use the same printf-style of argument passing. A formatting string which may be delimitted with variable placeholders (%d, %x, etc...) is followed by a list of program variables whose runtime values are substituted for those placeholders. Both printf-style system tasks behave identically. The only difference is that $display() automatically appends a newline character to the end of its output.

Scanf

The scan system task can be used to read values from stdin. However this feature is only useful when Cascade is used as a library, as when Cascade is run in a REPL, it dedicates stdin to parsing code.

Debugging Tasks

The debugging-family of system tasks can be used to print information about the program which Cascade is currently running. $list displays source code, $showvars displays information about program variables, and $showscopes displays information about program scopes.

Logging Tasks

The logging-family of system tasks behave identically to the printf-family of system tasks. The only difference is that their output can be filtered based on the arguments that you provide when you run Cascade. By default, $warning() and $error() messages are printed to the REPL. You can disable this behavior off by running Cascade with the --disable_warning and --disable_error flags. In contrast, $info() messages are not printed to the REPL by default. You can enable this behavior by running Cascade with the --enable_info flag.

Simulation Control Tasks

The $finish() system task can be used to shut Cascade down programmatically. Evaluating the $finish() task with an argument other than 0 will cause Cascade to emit a status message before shutting down. You can think of the $fatal() system task as a combination of the $finish() and $error() system tasks. The following two programs are identical.

initial $fatal(1, "format string %d", 42);
initial begin
  $error("format string %d", 42);
  $finish(1);
end

Virtualization Tasks

While Cascade was originally designed as a developer aid, its ability to break a program into pieces and move those pieces seamlessly between software and hardware turns out to be the key engineering primitive which is necessary for FPGA virtualization. The virtualization-family of system tasks expose this functionality.

The $save() and $restart() tasks can be used to save the state of a running program to a file, and then reload that state at a later tmie rather than having to run the program again from scratch. The following example shows how to configure two buttons to suspend and resume the execution of a program.

always @(pad.val) begin
  if (pad.val[0]) begin
    $save("path/to/file");
    $finish;
  end else if (pad.val[1]) begin
    $restart("path/to/file");
  end

The $retarget() task can be used to reconfigure Cascade as though it was run with a different --march file while a program is executing. This may be valuable for transitioning a running program from one hardware target to another. The following example shows how to configure two buttons to toggle the use of JIT-compilation mid-execution.

always @(pad.val) begin
  if (pad.val[0]) begin
    $retarget("de10");
  end else bif (pad.val[1]) begin
    $retarget("de10_jit");
  end
end

File I/O Tasks

The family of file i/o tasks provide an abstract mechanism for interacting with file streams. The following example shows how to read the contents of a file, one cycle at a time. Note that $fread() is sensitive to the size of its second argument and will read as many bytes as necessary to produce a value for that variable.

integer s = $fopen("path/to/file", "r");
reg[31:0] x = 0;

always @(posedge clock.val) begin
  $fread(s, x);
  if ($feof(s)) begin
    $finish;
  end
  $display(x);
end

The following example shows how you can use both $fread() and $fwrite() tasks in conjunction with the $feof task to stream data to and from your program, regardless of whether it is running in software or hardware.

module Compute(
  input  wire[31:0] x,
  output wire[31:0] y
);
  assign y = 2 * x;
endmodule;

reg[31:0]  x;
wire[31:0] y;
Compute c(x,y);

integer i = $fopen("path/to/input", "r");
integer o = $fopen("path/to/output");
always @(posedge clock.val) begin
  $fread(i, x);
  if ($feof(i)) begin
    $finish;
  end  
  $fwrite(o, "%x", y);
end

In addition to the tasks described above, the $fseek() task can be used to reset the position from which $fread() tasks are performed. Note that Cascade uses an eventual consistency model for $fdisplay() statements. Attempting to interleave reads and writes to the same stream may result in unexpected behavior unless the user forces a sync by invoking the $fflush() task.

Standard Library

In addition to supporting both synthesizable and unsynthesizable Verilog, Cascade also provides a Standard Library of I/O peripherals. You can think of this library as an abstract representation of target-specific hardware. By targeting the components in Cascade's Standard Library, rather than the specific peripherals associated with a hardware target, there is a good chance that your program will run in multiple environments without modification. We've already seen examples of many of the peripherals in Cascade's Standard Library. A complete listing, along with the --march targets which support them, is shown below.

Component sw de10 ulx3s
Clock x x x
Led x x
Pad x x
Reset x
GPIO x

Target-Specific Components

Some --march targets may instantiate modules which serve as wrappers around target-specific hardware features. For example, a target might provide a Bram module to expose a particular type of storage, or a Pcie module to expose a particular type of I/O. While these wrappers will typically expose the highest levels of performance to the user, they do so at the price of portability. Writing a program which relies on a particular low-level feature makes it unlikely that Cascade will be able to execute that program on an --march target other than the one it was designed for.

The target-specific hardware features exposed by an --march target, along with the standard library components it supports, can be displayed by running Cascade with the --enable_info flag.

Adding Support for New Backends

Adding support for a new backend begins with writing an --march file. This file will contain instantiations for the Standard Library components that your backend supports, as well as any target-specific components you wish to make available to the user. This file should also contain an $info() message which describes this support, along with anything else you'd like the user to know. Save this file as data/march/my_backend.v. Once you've done so, you can run Cascade with the --march my_backend flag. An example is shown below.

`ifndef __MY_BACKEND_V
`define __MY_BACKEND_V

// An --march file must first include the declarations in the Standard Library
`include "data/stdlib/stdlib.v"

// Next, an --march file must instantiate the root module. The __target annotation is 
// used to pass information to the Cascade compiler about how to compile the user's code. 
// __target is a semicolon-separated list of backend compilation passes to use. If only one 
// value is provided as below, then Cascade will not run in JIT-mode. To enable JIT-mode, 
// use the following string instead: "sw;my_backend".
(* __target="my_backend" *)
Root root();

// At a minimum, a backend must instantiate a global Standard Library clock
// which will never leave software. Any code which follows the instantiation of
// the root is placed inside of the root, and any instantiations which appear
// inside of the root inherit its annotations. The __target="sw" annotation
// overrides the value you placed on the root and guarantees that this module
// will never leave software simulation.
(* __target="sw" *)
Clock clock();

// This instantiation will expose an abstract bank of four Standard Library
// LEDs.  As above, the __target="my_backend" annotation overrides the value
// you placed on the root. This ensures that this module will be compiled
// directly to your backend rather than beginning execution in software
// simulation.
(* __target="my_backend" *)
Led#(4) led();

// This declaration will expose a target-specific pci connection.
// Target-specific declaration only need to specify their input and output
// pins. The actual implementation will be provided by your compiler.
module Pci();
  input wire ...
  output wire ...
endmodule

// This instantiation will expose your target-specific module. The __std="pci"
// annotation will be used to distinguish this instantiation from user code. As
// above, the __target="my_backend" annotation overrides the value you placed
// on the root.
(* __std="pci", __target="my_backend" *)
Pci pci();

// At this point you may have noticed that an  --march file is just Verilog
// code which is run before transferring control to the user. Now that your
// environment is set up, in addition to $info() statements, you could place
// any arbitrary code here as well. 
initial begin
  $info("My Backend");
  $info(" Supports the following Standard Library Components: Clock, Led");
  $info(" Supports the following Target-Specific Components: Pci");
end

`endif

Next, you'll need to create a compiler for your backend. Take a look at the CoreCompiler class which is defined in src/target/core_compiler.h. Your compiler must be a subclass of this type, and be able to compile user logic as well as instantiations of any of the Standard Library components you introduced in your --march file. For the example shown above, this means that you would need to override the following methods:

virtual Led* compile_led(Interface* interface, ModuleDeclaration* md);
virtual Logic* compile_logic(Interface* interface, ModuleDeclaration* md);

Additionally, because the example contains at least one target-specific component, you would also need to override the following method:

virtual Custom* compile_custom(Interface* interface, ModuleDeclaration* md);

Details on implementing these methods can be found in src/target/core_compiler.h. In short, the goal of this class is transform a ModuleDeclaration (Verilog source code) for an instantiated module into a Core (target-specific executable implementation of that code), of which Led, Logic, and Custom are sub-types, whose implementation relies on an Interface (which will be compiled for you) to communicate back and forth with the Cascade runtime as necessary.

The definitions for Core and Interface can be found in src/target/core.h and src/target/interface.h respectively. Your compiler will need to return target-specific instances of these classes. Both files contain detailed information on the invariants that Cascade imposes on the implementation of a Core and the functionality provided by an Interface. Briefly, a Core is responsible for implementing support for the Cascade runtime ABI. This ABI is the mechanism by which Cascade orchestrates the communication and computation necessary to satisfy the semantics of Verilog while at the same time providing support for the just-in-time features described above.

Once you've finished implementing your compiler, you'll need to register it by adding a few lines of code to src/cascade/cascade.cc.

Cascade::Cascade() : eval_(this), iostream(&sb_), sb_() {
  // ...
  runtime_.get_compiler()->set("sw", new SwCompiler());
  runtime_.get_compiler()->set("my_backend", new MyBackendCompiler());
  // ...
}

Rebuild your source and... everything should just work... Happy debugging!

FAQ

Flex fails during build with an error related to yyin even though I'm using version 2.6 or greater.

Some package managers fail to update the flex header file FlexLexer.h when upgrading versions. Locate your copy of FlexLexer.h and look up the definition of yyFlexLexer::yyin. If this variable has type std::istream*, your file is out of date and you will need to patch it. The current version of this file, which should have been installed can be found in Flex's top-level src/ directory.

Cascade emits strange warnings whenever I declare a module.

Module declarations are typechecked in the global scope, separate from the rest of your program. While this allows Cascade to catch many errors at declaration-time, there are some properties of Verilog programs which can only be verified at instantiation-time. If Cascade emits a warning, it is generally because it cannot statically prove that the module you declared will instantiate correctly in every possible program context.

Why does Cascade warn that x is undeclared when I declare Foo, but not when I instantiate it (Part 1)?

localparam x = 0;
module Foo();
  wire q = x;
endmodule
Foo f();

The local parameter x was declared in the root module, and the module Foo was declared in its own scope. In general, there is no way for Cascade to guarantee that you will instantiate Foo in a context where all of its declaration-time unresolved variables will be resolvable. In this case, it is statically provable, but Cascade doesn't know how to do so. When Foo is instantiated, Cascade can verify that there is a variable named p which is reachable from the scope in which f appears. No further warnings or errors are necessary. Here is a more general example:

module Foo();
  assign x.y.z = 1;
endmodule

// ...
begin : x
  begin : y
    reg z;
  end
end
// ...
Foo f(); // This instantiation will succeed because a variable named z
         // is reachable through the hierarchical name x.y.z from f.
         
// ...
begin : q
  reg r;
end
// ...
Foo f(); // This instantiation will fail because the only variable
         // reachable from f is q.r.

Why does Cascade warn that x is undeclared when I declare Foo, but not when I instantiate it (Part 2)?

module #(parameter N) Foo();
  genvar i;
  for (i = 0; i < N; i=i+1) begin : GEN
    reg x;
  end
  wire q = GEN[5].x;
endmodule
Foo#(8) f();

The register x was declared in a loop generate construct with bounds determined by a parameter. In general, there is no way for Cascade to guarantee that you will instantiate Foo with a parameter binding such that all of its declaration-time unresolved variables are resolvable. When Foo is instantiated with N=8, Cascade can verify that there is a variable named GEN[5].x. No further warnings or errors are necessary.

More generally, Cascade will defer typechecking for code that appears inside of generate constructs until instantiation-time.

I get it, but it seems like there's something about pretty much every module declaration that Cascade can't prove.

The truth hurts. Remember that if you'd like to disable warnings you can type.

$ cascade --disable_warning

More Repositories

1

kubeless

Kubernetes Native Serverless Framework
Go
6,867
star
2

clarity

Clarity is a scalable, accessible, customizable, open source design system built with web components. Works with any JavaScript framework, built for enterprises, and designed to be inclusive.
TypeScript
6,456
star
3

octant

Highly extensible platform for developers to better understand the complexity of Kubernetes clusters.
Go
6,247
star
4

kubewatch

Watch k8s events and trigger Handlers
Go
2,448
star
5

scripted

The Scripted code editor
JavaScript
1,564
star
6

eventrouter

A simple introspective kubernetes service that forwards events to a specified sink.
Go
873
star
7

tgik

Official repository for TGI Kubernetes (TGIK)!
Shell
828
star
8

kube-prod-runtime

A standard infrastructure environment for Kubernetes
Jsonnet
776
star
9

healthcheck

A library for implementing Kubernetes liveness and readiness probe handlers in your Go application.
Go
675
star
10

pivotal_workstation

A cookbook of recipes for an OSX workstation
662
star
11

cabin

The Mobile Dashboard for Kubernetes
JavaScript
659
star
12

dispatch

Dispatch is a framework for deploying and managing serverless style applications.
Go
535
star
13

buildkit-cli-for-kubectl

BuildKit CLI for kubectl is a tool for building container images with your Kubernetes cluster
Go
491
star
14

haret

A strongly consistent distributed coordination system, built using proven protocols & implemented in Rust.
Rust
462
star
15

concourse-pipeline-samples

Sample code and recipes for Concourse CI pipelines and deployments.
Shell
447
star
16

projectmonitor

Big Visible Chart CI aggregator
Ruby
427
star
17

kubeless-ui

Graphical User Interface for Kubeless
JavaScript
417
star
18

halite

DEPRECATED: A client-side web application interface to a running Salt infrastructure
Python
413
star
19

gangway

An application that can be used to easily enable authentication flows via OIDC for a kubernetes cluster.
Go
407
star
20

salty-vagrant

Use Salt as a Vagrant provisioner.
Shell
373
star
21

liota

Python
336
star
22

lightwave

Identity services for traditional infrastructure, applications and containers.
C
321
star
23

rbvmomi

Ruby interface to the VMware vSphere API.
Ruby
302
star
24

git_scripts

Developer workflow convenience scripts
Ruby
279
star
25

pcfdev

This is the depricated version of PCF Dev - please visit the current Github repository https://github.com/cloudfoundry-incubator/cfdev for the latest updates
Go
273
star
26

springsource-cloudfoundry-samples

Samples for Cloud Foundry
Java
259
star
27

admiral

Container management solution with an accent on modeling containerized applications and provide placement based on dynamic policy allocation
Java
254
star
28

vsphere-storage-for-docker

vSphere Storage for Docker
Python
254
star
29

salt-vim

Vim files for editing Salt files
Vim Script
246
star
30

rvc

RVC is a Linux console UI for vSphere, built on the RbVmomi bindings to the vSphere API.
Ruby
238
star
31

xenon

Xenon - Decentralized Control Plane Framework
Java
226
star
32

database-stream-processor

Streaming and Incremental Computation Framework
Rust
222
star
33

raet

Reliable Asynchronous Event Transport Protocol
Python
208
star
34

salt-cloud

Salt Cloud Working group.
200
star
35

vsphere-automation-sdk-rest

REST (Postman and JavaScript) samples and API reference documentation for vSphere using the VMware REST API
197
star
36

cloud-init-vmware-guestinfo

A cloud-init datasource for VMware vSphere's GuestInfo interface
Python
192
star
37

jsunit

The original unit-testing framework for JavaScript. These days we use Jasmine (http://github.com/pivotal/jasmine) by default for JS testing; JsUnit is not actively developed or supported.
Java
173
star
38

sql_magic

Magic functions for using Jupyter Notebook with Apache Spark and a variety of SQL databases.
Jupyter Notebook
171
star
39

purser

Kubernetes Cloud Native Applications visibility
Go
171
star
40

pyvcloud

Python SDK for VMware vCloud Director
Python
170
star
41

salt-contrib

Salt Module Contributions
Python
170
star
42

powernsx

PowerShell module that abstracts the VMware NSX-v API to a set of easily used PowerShell functions
PowerShell
170
star
43

p4c-xdp

Backend for the P4 compiler targeting XDP
C
166
star
44

webcommander

Powerful, flexible, intuitive and most importantly simple. That is what a real automation solution should be. No matter how complicated the task is, we'd like to turn it into a single click. Is that possible? Not without webcommander :)
PowerShell
166
star
45

vcd-cli

Command Line Interface for VMware vCloud Director
Python
164
star
46

wardroom

A tool for creating Kubernetes-ready base operating system images.
Python
162
star
47

pcf-pipelines

PCF Pipelines
Shell
158
star
48

spring-boot-cities

A Spring Boot + Spring Data + Spring Cloud Connectors demo app
Java
149
star
49

kube-manifests

A collection of misc Kubernetes configs for various jobs, as used in Bitnami's production clusters.
Jsonnet
136
star
50

ktx

manage kubernetes cluster configs
Shell
133
star
51

pg_rewind

Tool for resynchronizing a Postgres database after failover
125
star
52

AndroidIntelliJStarter

An IntelliJ template project for android developers, pre-configured to work with Robolectric, Roboguice, an other common, useful Android libraries.
Java
125
star
53

vctl-docs

VMware vctl Docs
124
star
54

cimonitor

This project has been renamed to ProjectMonitor - http://github.com/pivotal/projectmonitor
121
star
55

tmux-config

Configuration and tools for tmux. Can be used as a Vim plugin.
Shell
121
star
56

PivotalMySQLWeb

PivotalMySQL*Web is a free Pivotal open source project, intended to handle the administration of a Pivotal MySQL Service Instance over the Web
JavaScript
120
star
57

salt-api

RETIRED: Generic, modular network access system
Python
112
star
58

atc

old - now lives in https://github.com/concourse/concourse
111
star
59

nsxansible

A set of example Ansible Modules using the above two projects as the basis
Python
110
star
60

pg2mysql

Tool for safely migrating from PostgreSQL to MySQL
Go
107
star
61

clarity-seed

This is a repository for a seed project that includes Clarity Design System's dependencies.
TypeScript
104
star
62

helm-crd

Experimental CRD controller for managing Helm releases
Go
103
star
63

fly

old - now lives in https://github.com/concourse/concourse
100
star
64

declarative-cluster-management

Declarative cluster management using constraint programming, where constraints are described using SQL.
Java
99
star
65

hillview

Big data spreadsheet
Java
99
star
66

cbapi

Carbon Black API Resources
Python
94
star
67

vmware-vcenter

VMware vCenter Module
Ruby
87
star
68

ModSecurity-envoy

ModSecurity V3 Envoy Filter
C++
86
star
69

springtrader

JavaScript
83
star
70

tic

Bit9 + Carbon Black Threat Intelligence
Python
80
star
71

runtimes

Kubeless function runtimes: https://kubeless.io/docs/runtimes/
C#
79
star
72

pyvmomi-tools

Additional community developed python packages to help you work with pyvmomi
Python
77
star
73

gpdb-sandbox-tutorials

76
star
74

salt-windows-install

Open source installer for Windows
75
star
75

vagrant-vmware-appcatalyst

Vagrant provider for VMware AppCatalyst®
Ruby
73
star
76

transport-go

Transport is a full stack, simple, fast, expandable application event bus for your applications. It provides a standardized and simple API, implemented in multiple languages, to allow any individual component inside your applications to talk to one another. This is the Golang implementation of the Transport library.
Go
72
star
77

concord

🧱⛓️ A scalable decentralized blockchain
C++
71
star
78

terraforming-gcp

use terraform, deploy yourself a pcf
HCL
71
star
79

functions

Functions Repository for Kubeless
Python
70
star
80

Pivotal-Preferences-RubyMine

This repo is deprecated. Use the "Pivotal IDE Prefs" repo instead.
70
star
81

IoT-ConnectedCar

HTML
69
star
82

ironclad

Web Application Firewall (WAF) on Kubernetes
Go
69
star
83

vsphere-automation-sdk-.net

[DEPRECATED] Please see README. C# samples, language bindings, and API reference documentation for vSphere, VMC, and NSX-T using the VMware REST API
C#
67
star
84

pymadlib

A Python wrapper for MADlib(http://madlib.net) - an open source library for scalable in-database machine learning algorithms
Jupyter Notebook
65
star
85

chaperone

Python
64
star
86

bin

old - now lives in https://github.com/concourse/concourse
64
star
87

terraforming-aws

Templates to deploy PCF and PKS
HCL
64
star
88

legacy-terraform-provider-vra7

Terraform provider for vRealize Automation 7
Go
62
star
89

tutorials

PHP
59
star
90

nsxraml

A RAML Specification Describing the NSX for vSphere API
HTML
59
star
91

vra-api-samples-for-postman

API use case samples in Postman Rest Client collection format.
58
star
92

simple-k8s-test-env

For developers building and testing Kubernetes and core Kubernetes components
Shell
58
star
93

vm-operator-api

A client API for the VM Operator project, designed to allow for integration with vSphere 7 with Kubernetes
Go
58
star
94

gcp-pcf-quickstart

Install Pivotal Cloud Foundry on Google Cloud Platform With One Command
Go
56
star
95

sunspot_matchers

RSpec matchers for testing Sunspot searches
Ruby
56
star
96

ansible-security-hardening

ansible playbooks for linux distro security hardening
56
star
97

lobot

This project has been renamed to ciborg. Please visit the ciborg page for more info.
Ruby
56
star
98

salt-pack

Salt Package Builder
Shell
55
star
99

sublime-text

Salt-related syntax highlighting and snippets for Sublime Text
JavaScript
54
star
100

pynsxv

PyNSXv is a high level python based library and CLI tool to control NSX for vSphere
Python
54
star