{"id":13645614,"url":"https://github.com/vmware-archive/cascade","last_synced_at":"2025-04-21T14:32:04.254Z","repository":{"id":66819577,"uuid":"147731281","full_name":"vmware-archive/cascade","owner":"vmware-archive","description":"A Just-In-Time Compiler for Verilog from VMware Research","archived":true,"fork":false,"pushed_at":"2021-07-01T14:03:05.000Z","size":20184,"stargazers_count":444,"open_issues_count":15,"forks_count":44,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-04-18T18:11:41.363Z","etag":null,"topics":["fpga","hardware","jit","just-in-time","repl","verilog"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vmware-archive.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-09-06T20:43:23.000Z","updated_at":"2025-04-11T14:12:22.000Z","dependencies_parsed_at":"2023-07-08T10:01:24.811Z","dependency_job_id":null,"html_url":"https://github.com/vmware-archive/cascade","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vmware-archive%2Fcascade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vmware-archive%2Fcascade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vmware-archive%2Fcascade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vmware-archive%2Fcascade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vmware-archive","download_url":"https://codeload.github.com/vmware-archive/cascade/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250070250,"owners_count":21369842,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fpga","hardware","jit","just-in-time","repl","verilog"],"created_at":"2024-08-02T01:02:38.467Z","updated_at":"2025-04-21T14:32:00.910Z","avatar_url":"https://github.com/vmware-archive.png","language":"C++","readme":"! VMware has ended active development of this project, this repository will no longer be updated.\n![alt text](LOGO.png \"Cascade: A JIT Compiler for Verilog from VMware Research\")\n---\n[![Build Status](https://img.shields.io/travis/com/vmware/cascade/master.svg?style=flat-square)](https://travis-ci.com/vmware/cascade)\n[![Coverage Status](https://img.shields.io/codecov/c/github/vmware/cascade.svg?style=flat-square)](https://codecov.io/gh/vmware/cascade)\n\nFPGAs can exceed the performance of general-purpose CPUs by several orders of\nmagnitude and offer dramatically lower cost and time to market than ASICs.\nWhile the benefits are substantial, programming an FPGA can be an extremely\nslow process. Trivial programs can take several minutes to compile using a\ntraditional compiler, and complex designs can take hours or longer. \n\nCascade is a novel solution to this problem, the world's first just-in-time\ncompiler for Verilog. Cascade executes code immediately in a software\nsimulator, and performs compilation in the background. When compilation is\nfinished, the code is moved into hardware, and from the user’s perspective it\nsimply gets faster over time. Cascade's ability to move code back and forth\nbetween software and hardware also makes it the first platform to provide\ngeneric support for the execution of unsynthesizable Verilog from hardware. The\neffects are substantial. Cascade encourages more frequent compilation, reduces\nthe time required for developers to produce working hardware designs, and\ntransforms HDL development into something which closely resembes writing\nJavaScript or Python. It takes the first steps towards bridging the gap between\nprogramming software and programming hardware.\n\nMuch of the work which has gone into building Cascade has been documented in\nconference proceedings. A complete list of publications (hopefully with more to\ncome) is below. Note however, that Cascade is under active development. In some\ncases, its implementation may have diverged what is described in these\ntexts. The most up-to-date information on Cascade's implementation is always\nits source code.\n\n- [**Just-in-Time Compilation for Verilog** -- ASPLOS 2019](https://raw.githubusercontent.com/vmware/cascade/master/share/cascade/doc/asplos19.pdf)\n\nRecent Updates:\n\n* **12/19** Cascade supports the [ULX3S](https://radiona.org/ulx3s/) as a backend target.\n* **11/19** Cascade uses [Verilator](https://www.veripool.org/wiki/verilator) as an intermediate compilation pass between software simulation and hardware.\n* **10/19** Cascade provides experimental support for Xilinx FPGAs on Amazon F1 (release coming soon).\n* **9/19** Cascade can be linked into C++ projects as a library. This allows Cacade to target itself as a backend target.\n* **7/19** Cascade supports unsynthesizable file I/O primitives from hardware.\n* **5/19** Cascade supports the [DE10 Nano](https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English\u0026No=1046) as a backend target.\n\nIndex\n=====\n0. [Dependencies](#dependencies)\n1. [Building Cascade](#building-cascade)\n2. [Using Cascade](#using-cascade)\n    1. [Command Line Interface](#command-line-interface)\n    2. [As a Library](#as-a-library)\n3. [Environments](#environments)\n    1. [Software Backend](#software-backend)\n    2. [Hardware Backends](#hardware-backends)\n        1. [DE10 Nano](#de10-nano)\n        2. [ULX3S](#ulx3s)\n    3. [JIT Compilation](#jit-compilation)\n4. [Support for Synthesizable Verilog](#support-for-synthesizable-verilog)\n5. [Support for Unsynthesizable Verilog](#support-for-unsynthesizable-verilog)\n6. [Standard Library](#standard-library)\n7. [Target-Specific Components](#target-specific-components)\n8. [Adding Support for New Backends](#adding-support-for-new-backends)\n9. [FAQ](#faq)\n\nDependencies\n=====\nCascade should build successfully on OSX and most Linux distributions. \n\nBuilding Cascade\n=====\n1. Clone this repository \n```\n$ git clone https://github.com/vmware/cascade\n```\n\n2. Run the setup script\n\n```bash\n$ cd cascade\n$ ./setup\n```\n\nThe setup script should guide you through installing dependencies, as\nwell as configuring, building and testing Cascade.\n\nUsing Cascade\n=====\n\n### Command Line Interface\n\nStart Cascade by typing\n```\n$ cascade\n```\nThis will place you in a Read-Evaluate-Print-Loop (REPL). Code which is typed\nhere is appended to the source of the (initially empty) top-level (root) module\nand evaluated immediately. Try defining a wire. \n```verilog\n\u003e\u003e\u003e wire x;\n```\nThe Verilog specification requires that code inside of ```initial``` blocks is\nexecuted exactly once when a program begins executing. Because Cascade is a\ndynamic environment, we generalize that specification: code inside of\n```initial``` blocks is executed exactly once immediately after it is compiled.\nTry printing the value of the wire you just defined. Cascade uses a two-value model\nfor signals. Unknown logic values (X) are set to zero, and high-impedence values (Z)\nare assigned non-deterministic values.\n```verilog\n\u003e\u003e\u003e initial $display(x);\n\u003e\u003e\u003e 0\n```\nNow try printing a variable which hasn't been defined.\n```verilog\n\u003e\u003e\u003e initial $display(y);\n\u003e\u003e\u003e Typechecker Error:\n\u003e\u003e\u003e  \u003e In final line of user input:\n\u003e\u003e\u003e    Referenece to unresolved identifier: y\n```\nAnything you enter into the REPL is lexed, parsed, type-checked, and compiled.\nIf any part of this process fails, Cascade will produce an error message and\nthe remainder of your text will be ignored. If you type multiple statements,\nanything which compiles successfully before the error is encountered cannot be\nundone. Below, ```x``` and ```y``` are declared successfully, but the\nredeclaration of ```x``` produces an error.\n```verilog\n\u003e\u003e\u003e wire x,y,x;\n\u003e\u003e\u003e Typechecker Error:\n\u003e\u003e\u003e  \u003e In final line of user input:\n\u003e\u003e\u003e    A variable named x already appears in this scope.\n\u003e\u003e\u003e    Previous declaration appears in previous user input.\n\u003e\u003e\u003e initial $display(y);\n\u003e\u003e\u003e 0\n```\nYou can declare and instantiate modules from the REPL as well. Note however,\nthat  declarations will be type-checked in the global  scope. Variables which\nyou may have declared in the root module will not be visible here. It isn't\nuntil a module is instantiated that it can access program state.\n```verilog\n\u003e\u003e\u003e module Foo(\n\u003e\u003e\u003e   input wire x,\n\u003e\u003e\u003e   output wire y \n\u003e\u003e\u003e );\n\u003e\u003e\u003e   assign y = x;\n\u003e\u003e\u003e endmodule\n\u003e\u003e\u003e wire q,r;\n\u003e\u003e\u003e Foo f(q,r);\n```\nIf you don't want to type your entire program into the REPL you can use the\ninclude statement, where ```path/``` is assumed to be relative to your current\nworking directory.\n```verilog\n\u003e\u003e\u003e `include \"path/to/file.v\"\n```\nIf you'd like to use additional search paths, you can start Cascade using the\n```-I``` flag and provide a list of semicolon-separated alternatives. Cascade\nwill try each of these paths as a prefix, in order, until it finds a match.\n```\n$ cascade -I path/to/dir1:path/to/dir2\n```\nAlternately, you can start Cascade with the ```-e``` flag and the name of a file to include.\n```\n$ cascade -e path/to/file.v\n```\nFinally, Cascade will stop running whenever a program invokes the ```$finish``` task.\n```verilog\n\u003e\u003e\u003e initial $finish;\nGoodbye!\n```\nYou can also force a shutdown by typing ```Ctrl-C``` or ```Ctrl-D```.\n```verilog\n\u003e\u003e\u003e module Foo(); wir... I give up... arg... ^C\n```\n\n### As a Library\n\nCascade can also be called directly from C++ code. Cascade's command line interface\nis a thin-wrapper around a small set of functions. A minimal example \nis shown below. Further dicussion of the concepts in this example appears in subsequent\nsections of this README. \n\n```c++\n#include \u003ccassert\u003e\n#include \u003ciostream\u003e\n#include \u003csstream\u003e\n#include \u003ccascade.h\u003e\n\nusing namespace cascade;\nusing namespace std;\n\nint main() {\n    // Create an instance of Cascade. Cascade is thread-safe. Multiple instances\n    // may share the same address space.\n    Cascade cascade;\n    \n    // Configuration options. These methods should all be called before\n    // cascade starts running.\n    cascade.set_include_dirs(...);\n    cascade.set_enable_inlining(...);\n    cascade.set_open_loop_target(...);\n    cascade.set_quartus_server(...);\n    cascade.set_profile_interval(...);\n\n    // Cascade exposes its six i/o streams (the standard STDIN, STDOUT, and\n    // STDERR, along with  three additional STDWARN, STDINFO, STDLOG) as\n    // C++ streambufs. These are initially mapped to nullptr. Changes to this\n    // mapping should also be made before cascade starts running.\n    cascade.set_stdin(cin.rdbuf());\n    cascade.set_stdout(cout.rdbuf());\n    cascade.set_stderr(cerr.rdbuf());\n    cascade.set_stdwarn(cerr.rdbuf());\n    cascade.set_stdinfo(clog.rdbuf());\n    cascade.set_stdlog(...);\n    \n    // Start cascade. This method returns immediately.\n    cascade.run();\n    \n    // Cascade will run until the user's program invokes the $finish() task or the \n    // user requests that it stop running. The request_stop() method returns immediately. \n    // The wait_for_stop() method will block until either of the above conditions\n    // is satisified.\n    cascade.request_stop();\n    cascade.wait_for_stop();\n    \n    // Stopping cascade only pauses its execution. All previous state is retained.\n    // To continue running, call run() again.\n    cascade.run();\n    \n    // Cascade is a c++ ostream. While it is running, any text provided to it\n    // via the \u003c\u003c operator, will be eval'ed. Since every program must begin with an\n    // march file, you can use an include statement to eval one.\n    cascade \u003c\u003c \"`include \\\"path/to/march.v\\\"\";\n    \n    // Because cascade runs asynchronously, it has no way of knowing when user input\n    // has ended. The user can force this by using the flush() method, or passing \n    // cascade a c++ endl. Be careful with using endl to separate multi-line inputs.\n    // This may cause cascade to prematurely evaluate user input. When in doubt, prefer '\\n'.\n    cascade.flush(); \n    cascade \u003c\u003c endl;\n    \n    // The results of the eval statements which have taken place since the previous\n    // flush are available through ostream status bits. Cascade is placed in\n    // in the eof state when it encounters an eof character, and in the bad state when\n    // an eval results in a parse or type error. Because cascade runs asynchronously, the \n    // only way to make sure an eval has run to completion is to request a stop. The standard\n    // mechanism for clearing an ostream's state bits is to use the clear() method.\n    \n    assert(!cascade.bad()); // Not guaranteed to see the result of the previous eval.\n    cascade.stop_now(); // Syntactic sugar for request_stop(); wait_for_stop();\n    assert(!cascade.bad()); // Both guaranteed to see the result of the previous eval.\n    assert(!cascade.eof()); \n    cascade.clear(); // Clears eof and bad bits.\n    \n    // While cascade is stopped, it is safe to replace its rdbuf. For example:\n    stringstream ss(\"wire x; initial $display(\\\"Hello, world!\\\");\");\n    cascade.rdbuf(ss.rdbuf());\n    cascade.run();\n    \n    // Note however, that most c++ implementations assign non-standard semantics to\n    // cin. It's safe to switch cascade's rdbuf to cin. But once this is done, it is\n    // no longer safe to change it again.\n    cascade.stop_now();\n    cascade.rdbuf(cin.rdbuf());\n    cascade.rdbuf(ss.rdbuf()); // UNDEFINED!\n    cascade.run();\n    \n    // Block until the user's program invokes the $finish() task.\n    cascade.wait_for_stop();\n\n    return 0;\n}\n```\n\nTo build a program that uses Cascade as a library, statically link against libcascade. If you installed cascade to a directory\nother than ```/usr/local/``` you'll need to provide alternate values for the ```-I``` and ```-L``` flags.\n\n```\n$ g++ --std=c++17 -I/usr/local/include/cascade my_program.cc -lcascade\n```\n\nEnvironments\n=====\n\n### Software Backend\nBy default, Cascade runs in software. You can invoke this\nbehavior explicitly using the ```--sw``` flag.\n```\n$ cascade --march sw\n```\nThis environment declares the following module and instantiates it into the\ntop-level module for you:\n```verilog\nmodule Clock(\n  output wire val\n);\nendmodule\n\nClock clock;\n```\nThis module represents the global clock. Its value toggles between zero and one\nevery cycle. Try typing the following (and remember that you can type Ctrl-C to\nquit):\n```verilog\n\u003e\u003e\u003e always @(clock.val) $display(clock.val);\n\u003e\u003e\u003e 0\n\u003e\u003e\u003e 1\n\u003e\u003e\u003e 0\n\u003e\u003e\u003e 1\n\u003e\u003e\u003e ...\n```\nThis global clock can be used to implement sequential circuits, such as the\nbarrel shifter shown below.\n```verilog\n\u003e\u003e\u003e module BShift(\n\u003e\u003e\u003e   input wire clk,\n\u003e\u003e\u003e   output reg[7:0] val\n\u003e\u003e\u003e );\n\u003e\u003e\u003e   always @(posedge clk) begin\n\u003e\u003e\u003e     val \u003c= (val == 8'h80) ? 8'h01 : (val \u003c\u003c 1);\n\u003e\u003e\u003e   end\n\u003e\u003e\u003e endmodule\n\u003e\u003e\u003e wire[7:0] x;\n\u003e\u003e\u003e BShift bs(clock.val, x);\n```\nCompared to a traditional compiler which assumes a fixed clock rate, Cascade's\nclock is *virtual*: the amount of time between ticks can vary from one cycle to\nthe next, and is a function of both how large your program and is and how often\nand how much I/O it performs. This abstraction is the key mechanism by which\nCascade is able to move programs between software and hardware without\ninvolving the user.  \n\nUp until this point the code we've looked at has been entirely compute-based. \nHowever most hardware programs involve the use of I/O\nperipherals. Before we get into real hardware, first try running Cascade's\nvirtual software FPGA.\n```\n$ sw_fpga\n```\nCascade's virtual FPGA provides an ncurses GUI with four buttons, one reset,\nand eight leds. You can toggle the buttons using the ```1 2 3 4``` keys, toggle\nthe reset using the ```r``` key, and shut down the virtual FPGA by typing\n```q```. Cascade's software backend will automatically detect the virtual FPGA and expose its peripherals\nas modules which are implicitly declared and instantiated in the top-level\nmodule:\n```verilog\nmodule Pad(\n  output wire[3:0] val\n);\nendmodule\nPad pad();\n\nmodule Reset(\n  output wire val\n);\nendmodule\nReset reset();\n\nmodule Led(\n  output wire[7:0] val\n);\nendmodule\nLed led();\n```\nTry writing a simple program that connects the pads to the leds.\n```verilog\n\u003e\u003e\u003e assign led.val = pad.val;\n```\nToggling the pads should now change the values of the leds for as long as\nCascade is running.\n\n### Hardware Backends\nCascade currently provides support for two hardware backends: the [Terasic\nDE10 Nano\nSoC](https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English\u0026No=1046)\nand the [ULX3S](https://radiona.org/ulx3s/). When Cascade is run on either of these targets, instead of mapping compute and leds\nonto virtual components, it can map them directly onto real hardware.\n\n### DE10 Nano\n\nBefore using the de10 backend you'll first need to install [Intel's Quartus Lite IDE](http://fpgasoftware.intel.com/?edition=lite) on a network-accessible 64-bit Linux machine. You'll also need to run Cascade's compilation server on that machine.\n```\n$ quartus_server --path \u003cquartus/install/dir\u003e --port 9900\n```\n\nAlternatively, you can use Quartus Lite IDE installed on a remote host:\n```\n$ quartus_server --tunnel-command \u003ccommand/like/ssh\u003e --path \u003cquartus/install/dir\u003e --port 9900\n```\n\nNext you'll need an SD card image for your DE10 with a valid installation of Cascade. Cascade can generate\nthis image for you automatically or you can download a prebuilt image [here (todo)](todo). Reboot your DE10 using this image and run Cascade as usual (but on the DE10, use sudo).\n```\n$ cd cascade\n$ sudo cascade --march de10 --quartus_host \u003c64-bit Linux IP\u003e --quartus_port \u003c64-bit Linux port\u003e\n```\n\nAssuming Cascade is able to successfully connect to the FPGA fabric, you will\nbe presented with a similar environment to the one you encountered when using the software backend. The only\ndifference is that instead of a Reset module, Cascade will implicitly declare\nthe following module, which represents the DE10's Arduino header.\n```verilog\nmodule GPIO(\n  input wire[7:0] val\n);\nendmodule\nGPIO gpio();\n```\n\nTry repeating the example from the previous section and watch real buttons\ntoggle real leds.\n\n### ULX3S\n\nCascade supports the ULX3S using the entirely open source [Yosys](http://www.clifford.at/yosys/)-\u003e[NextPNR](https://github.com/YosysHQ/nextpnr)-\u003e[ujprog](https://github.com/f32c/tools/tree/master/ujprog) toolchain. Before getting started, you'll need to follow the directions [here](https://github.com/SymbiFlow/prjtrellis) for installing Yosys and NextPNR, and [here](https://github.com/f32c/tools/tree/master/ujprog) for installing ujprog. Make sure that all components are installed to the standard ```/usr/local``` directory tree.\n\nNext, you should be able to run Cascade as usual.\n``` bash\n$ cascade --march ulx3s\n```\n\nCascade 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.\n\n### JIT Compilation\n\nIf you'd like more information on how Cascade transitions  code between\nsoftware and hardware, trying using the ```--enable_info``` flag. This will cause Cascade to print\nstatus updates to the REPL whenever part of your program begins execution in a new context.\n``` bash\n$ cascade --enable_info\n```\n\nIn general, you can expect your virtual clock frequency to increase as more and more of your logic\ntransitions to hardware. Providing the ```--profile \u003cn\u003e``` flag will cause Cascade to periodically (every\n\u003cn\u003e 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.\n```\n$ cascade --march \u003csw|de10|ulx3s\u003e -e share/cascade/test/benchmark/bitcoin/run_25.v --enable_info --profile 3\n```\n\nSupport for Synthesizable Verilog\n=====\nCascade currently supports a large --- though certainly not complete --- subset\nof the Verilog 2005 Standard. The following partial list should give a good\nimpression of what Cascade is capable of.\n\n| Feature Class         | Feature                   | Supported | In Progress | Will Not Support | \n|:----------------------|:--------------------------|:---------:|:-----------:|:----------------:|\n| Compiler Directives   | `define                   |  x        |             |                  |\n|                       | `undef                    |  x        |             |                  |\n|                       | `ifdef                    |  x        |             |                  |\n|                       | `ifndef                   |  x        |             |                  |\n|                       | `elsif                    |  x        |             |                  |\n|                       | `else                   w  |  x        |             |                  |\n|                       | `endif                    |  x        |             |                  |\n|                       | `include                  |  x        |             |                  |\n| Primitive Types       | Net Declarations          |  x        |             |                  |\n|                       | Reg Declarations          |  x        |             |                  |\n|                       | Integer Declarations      |  x        |             |                  |\n|                       | Real Declarations         |  x        |             |                  |\n|                       | Time Declarations         |  x        |             |                  |\n|                       | Realtime Declarations     |  x        |             |                  |\n|                       | Array Declarations        |  x        |             |                  |\n| Expressions           | Arithmetic Operators      |  x        |             |                  |\n|                       | Bitwise Operators         |  x        |             |                  |\n|                       | Logical Operators         |  x        |             |                  |\n|                       | Concatentation Operators  |  x        |             |                  |\n|                       | Conditional Operators     |  x        |             |                  |\n|                       | Bit/Part Select           |  x        |             |                  |\n|                       | Strings                   |  x        |             |                  |\n|                       | Real Constants            |  x        |             |                  |\n| Parameters            | Parameter Declarations    |  x        |             |                  |\n|                       | Localparam Declarations   |  x        |             |                  |\n|                       | Defparam Statements       |           |             | x                |\n| Module Declarations   | Input Ports               |  x        |             |                  |\n|                       | Output Ports              |  x        |             |                  |\n|                       | Inout Ports               |           |             | x                |\n| Module Instantiations | Named Parameter Binding   |  x        |             |                  |\n|                       | Ordered Parameter Binding |  x        |             |                  |\n|                       | Named Port Binding        |  x        |             |                  |\n|                       | Ordered Port Binding      |  x        |             |                  |\n|                       | Instantiation Arrays      |           | x           |                  |\n| Generate Constructs   | Genvar Declarations       |  x        |             |                  |\n|                       | Case Generate Constructs  |  x        |             |                  |\n|                       | If Generate Constructs    |  x        |             |                  |\n|                       | Loop Generate Constructs  |  x        |             |                  |\n\nSupport for Unsynthesizable Verilog\n=====\n\nCascade provides support for many of the unsynthesizable system tasks which are\ndescribed in the 2005 specification, along with a few others which are unique\nto a just-in-time enviornment. One of the things that makes Cascade so powerful\nis that it supports the execution of unsynthesizable systems tasks *even when a\nprogram is running in hardware*. With Cascade, there's no reason to shy away\nfrom the use of ```$display()``` as a debugging tool. Unsynthesizable system\ntasks are guaranteed to run correctly on every target.\n\nA complete listing of the system tasks which Cascade supports, along with a\nbrief description of their behavior is shown below.\n\n| Feature Class         | Feature                     | Supported | In Progress | Will Not Support | \n|:----------------------|:----------------------------|:---------:|:-----------:|:----------------:|\n| Printf                | $display(fmt, args...)      |  x        |             |                  |\n|                       | $write(fmt, args...)        |  x        |             |                  |\n| Scanf                 | $scanf(fmt, args...)        |  x        |             |                  |\n| Debugging             | $monitor(var)               |           | x           |                  |\n|                       | $list(name)                 |  x        |             |                  |\n|                       | $showscopes(n)              |  x        |             |                  |\n|                       | $showvars(vars...)          |  x        |             |                  |\n| Logging               | $info(fmt, args...)         |  x        |             |                  |    \n|                       | $warning(fmt, args...)      |  x        |             |                  |\n|                       | $error(fmt, args...)        |  x        |             |                  |\n| Simulation Control    | $finish(code)               |  x        |             |                  |\n|                       | $fatal(code, fmt, args...)  |  x        |             |                  |\n| Virtualization        | $save(file)                 |  x        |             |                  |\n|                       | $restart(file)              |  x        |             |                  |\n|                       | $retarget(march)            |  x        |             |                  |\n| File I/O              | $fopen(path, mode)          |  x        |             |                  |\n|                       | $fclose(fd)                 |           | x           |                  |\n|                       | $fdisplay(fd, fmt, args...) |  x        |             |                  |\n|                       | $feof(fd)                   |  x        |             |                  |\n|                       | $fflush(fd)                 |  x        |             |                  |\n|                       | $fgetc(fd)                  |           | x           |                  |\n|                       | $fgets(str, fd)             |           | x           |                  |\n|                       | $fread(fd, var)             |  x        |             |                  |\n|                       | $fscanf(fd, fmt, args...)   |  x        |             |                  |\n|                       | $fseek(fd, off, dir)        |  x        |             |                  |\n|                       | $ftell(fd)                  |           | x           |                  |\n|                       | $fwrite(fd, fmt, args...)   |  x        |             |                  |\n|                       | $rewind(fd, off, dir)       |  x        |             |                  |\n|                       | $ungetc(c, dir)             |           | x           |                  |\n\n\n#### Printf Tasks\n\nThe printf family of system tasks can be used to emit debugging statements to\nstdout (the REPL). Both use the same printf-style of argument passing. A\nformatting string which may be delimitted with variable placeholders (```%d,\n%x, etc...```) is followed by a list of program variables whose runtime values\nare substituted for those placeholders. Both printf-style system tasks behave\nidentically. The only difference is that ```$display()``` automatically appends\na newline character to the end of its output.\n\n#### Scanf\n\nThe scan system task can be used to read values from stdin. However this\nfeature is only useful when Cascade is used as a library, as when Cascade is\nrun in a REPL, it dedicates stdin to parsing code.\n\n### Debugging Tasks\n\nThe debugging-family of system tasks can be used to print information about\nthe program which Cascade is currently running. ```$list``` displays source code,\n```$showvars``` displays information about program variables, and ```$showscopes```\ndisplays information about program scopes.\n\n#### Logging Tasks\n\nThe logging-family of system tasks behave identically to the printf-family of\nsystem tasks. The only difference is that their output can be filtered based on\nthe arguments that you provide when you run Cascade. By default,\n```$warning()``` and ```$error()``` messages are printed to the REPL. You can\ndisable this behavior off by running Cascade with the ```--disable_warning```\nand ```--disable_error``` flags. In contrast, ```$info()``` messages are not\nprinted to the REPL by default. You can enable this behavior by running Cascade\nwith the ```--enable_info``` flag.\n\n#### Simulation Control Tasks\n\nThe ```$finish()``` system task can be used to shut Cascade down\nprogrammatically. Evaluating the ```$finish()``` task with an argument other\nthan 0 will cause Cascade to emit a status message before shutting down. You\ncan think of the ```$fatal()``` system task as a combination of the\n```$finish()``` and ```$error()``` system tasks. The following two programs are\nidentical.\n\n``` verilog\ninitial $fatal(1, \"format string %d\", 42);\n```\n``` verilog\ninitial begin\n  $error(\"format string %d\", 42);\n  $finish(1);\nend\n```\n\n#### Virtualization Tasks\n\nWhile Cascade was originally designed as a developer aid, its ability to break\na program into pieces and move those pieces seamlessly between software and\nhardware turns out to be the key engineering primitive which is necessary for\nFPGA virtualization. The virtualization-family of system tasks expose this\nfunctionality. \n\nThe ```$save()``` and ```$restart()``` tasks can be used to save the state of a\nrunning program to a file, and then reload that state at a later tmie rather\nthan having to run the program again from scratch. The following example shows\nhow to configure two buttons to suspend and resume the execution of a program.\n\n```verilog\nalways @(pad.val) begin\n  if (pad.val[0]) begin\n    $save(\"path/to/file\");\n    $finish;\n  end else if (pad.val[1]) begin\n    $restart(\"path/to/file\");\n  end\n```\n\nThe ```$retarget()``` task can be used to reconfigure Cascade as though it was\nrun with a different ```--march``` file while a program is executing. This may\nbe valuable for transitioning a running program from one hardware target to\nanother. The following example shows how to configure two buttons to toggle the\nuse of JIT-compilation mid-execution.\n\n```verilog\nalways @(pad.val) begin\n  if (pad.val[0]) begin\n    $retarget(\"de10\");\n  end else bif (pad.val[1]) begin\n    $retarget(\"de10_jit\");\n  end\nend\n```\n\n#### File I/O Tasks \n\nThe family of file i/o tasks provide an abstract mechanism for interacting with\nfile streams. The following example shows how to read the contents of a file,\none cycle at a time. Note that ```$fread()``` is sensitive to the size of its\nsecond argument and will read as many bytes as necessary to produce a value for\nthat variable.\n\n```verilog\ninteger s = $fopen(\"path/to/file\", \"r\");\nreg[31:0] x = 0;\n\nalways @(posedge clock.val) begin\n  $fread(s, x);\n  if ($feof(s)) begin\n    $finish;\n  end\n  $display(x);\nend\n```\n\nThe following example shows how you can use both ```$fread()``` and\n```$fwrite()``` tasks in conjunction with the ```$feof``` task to stream data\nto and from your program, regardless of whether it is running in software or\nhardware.\n\n```verilog\nmodule Compute(\n  input  wire[31:0] x,\n  output wire[31:0] y\n);\n  assign y = 2 * x;\nendmodule;\n\nreg[31:0]  x;\nwire[31:0] y;\nCompute c(x,y);\n\ninteger i = $fopen(\"path/to/input\", \"r\");\ninteger o = $fopen(\"path/to/output\");\nalways @(posedge clock.val) begin\n  $fread(i, x);\n  if ($feof(i)) begin\n    $finish;\n  end  \n  $fwrite(o, \"%x\", y);\nend\n```\n\nIn addition to the tasks described above, the ```$fseek()``` task can be used\nto reset the position from which ```$fread()``` tasks are performed. Note that\nCascade uses an eventual consistency model for ```$fdisplay()``` statements.\nAttempting to interleave reads and writes to the same stream may result in\nunexpected behavior unless the user forces a sync by invoking the\n```$fflush()``` task.\n\nStandard Library\n=====\n\nIn addition to supporting both synthesizable and unsynthesizable Verilog,\nCascade also provides a Standard Library of I/O peripherals. You can think of\nthis library as an abstract representation of target-specific hardware. By\ntargeting the components in Cascade's Standard Library, rather than the\nspecific peripherals associated with a hardware target, there is a good chance\nthat your program will run in multiple environments without modification. We've\nalready seen examples of many of the peripherals in Cascade's Standard Library.\nA complete listing, along with the ```--march``` targets which support them, is\nshown below.\n\n| Component | sw | de10 | ulx3s    |\n|:----------|:--:|:----:|:--------:|\n| Clock     | x  | x    | x        |\n| Led       | x  | x    |          |\n| Pad       | x  | x    |          |\n| Reset     | x  |      |          |\n| GPIO      |    | x    |          |\n\nTarget-Specific Components\n=====\n\nSome ```--march``` targets may instantiate modules which serve as wrappers\naround target-specific hardware features. For example, a target might provide a\n```Bram``` module to expose a particular type of storage, or a ```Pcie```\nmodule to expose a particular type of I/O. While these wrappers will typically\nexpose the highest levels of performance to the user, they do so at the price\nof portability. Writing a program which relies on a particular low-level\nfeature makes it unlikely that Cascade will be able to execute that program on\nan ```--march``` target other than the one it was designed for.\n\nThe target-specific hardware features exposed by an ```--march``` target, along\nwith the standard library components it supports, can be displayed by running\nCascade with the ```--enable_info``` flag.\n\nAdding Support for New Backends\n=====\n\nAdding support for a new backend begins with writing an ```--march``` file.\nThis file will contain instantiations for the Standard Library components that\nyour backend supports, as well as any target-specific components you wish to\nmake available to the user. This file should also contain an ```$info()```\nmessage which describes this support, along with anything else you'd like the\nuser to know. Save this file as ```data/march/my_backend.v```. Once you've done\nso, you can run Cascade with the ```--march my_backend``` flag. An example is\nshown below.\n\n```verilog\n`ifndef __MY_BACKEND_V\n`define __MY_BACKEND_V\n\n// An --march file must first include the declarations in the Standard Library\n`include \"data/stdlib/stdlib.v\"\n\n// Next, an --march file must instantiate the root module. The __target annotation is \n// used to pass information to the Cascade compiler about how to compile the user's code. \n// __target is a semicolon-separated list of backend compilation passes to use. If only one \n// value is provided as below, then Cascade will not run in JIT-mode. To enable JIT-mode, \n// use the following string instead: \"sw;my_backend\".\n(* __target=\"my_backend\" *)\nRoot root();\n\n// At a minimum, a backend must instantiate a global Standard Library clock\n// which will never leave software. Any code which follows the instantiation of\n// the root is placed inside of the root, and any instantiations which appear\n// inside of the root inherit its annotations. The __target=\"sw\" annotation\n// overrides the value you placed on the root and guarantees that this module\n// will never leave software simulation.\n(* __target=\"sw\" *)\nClock clock();\n\n// This instantiation will expose an abstract bank of four Standard Library\n// LEDs.  As above, the __target=\"my_backend\" annotation overrides the value\n// you placed on the root. This ensures that this module will be compiled\n// directly to your backend rather than beginning execution in software\n// simulation.\n(* __target=\"my_backend\" *)\nLed#(4) led();\n\n// This declaration will expose a target-specific pci connection.\n// Target-specific declaration only need to specify their input and output\n// pins. The actual implementation will be provided by your compiler.\nmodule Pci();\n  input wire ...\n  output wire ...\nendmodule\n\n// This instantiation will expose your target-specific module. The __std=\"pci\"\n// annotation will be used to distinguish this instantiation from user code. As\n// above, the __target=\"my_backend\" annotation overrides the value you placed\n// on the root.\n(* __std=\"pci\", __target=\"my_backend\" *)\nPci pci();\n\n// At this point you may have noticed that an  --march file is just Verilog\n// code which is run before transferring control to the user. Now that your\n// environment is set up, in addition to $info() statements, you could place\n// any arbitrary code here as well. \ninitial begin\n  $info(\"My Backend\");\n  $info(\" Supports the following Standard Library Components: Clock, Led\");\n  $info(\" Supports the following Target-Specific Components: Pci\");\nend\n\n`endif\n```\n\nNext, you'll need to create a compiler for your backend. Take a look at the\n```CoreCompiler``` class which is defined in ```src/target/core_compiler.h```.\nYour compiler must be a subclass of this type, and be able to compile user\nlogic as well as instantiations of any of the Standard Library components you\nintroduced in your ```--march``` file. For the example shown above, this means\nthat you would need to override the following methods:\n\n```c++\nvirtual Led* compile_led(Interface* interface, ModuleDeclaration* md);\nvirtual Logic* compile_logic(Interface* interface, ModuleDeclaration* md);\n```\n\nAdditionally, because the example contains at least one target-specific\ncomponent, you would also need to override the following method:\n\n```c++\nvirtual Custom* compile_custom(Interface* interface, ModuleDeclaration* md);\n```\n\nDetails on implementing these methods can be found in\n```src/target/core_compiler.h```. In short, the goal of this class is transform\na ```ModuleDeclaration``` (Verilog source code) for an instantiated module into\na ```Core``` (target-specific executable implementation of that code), of which\n```Led```, ```Logic```, and ```Custom``` are sub-types, whose implementation\nrelies on an ```Interface``` (which will be compiled for you) to communicate\nback and forth with the Cascade runtime as necessary.\n\nThe definitions for ```Core``` and ```Interface``` can be found in\n```src/target/core.h``` and ```src/target/interface.h``` respectively. Your\ncompiler will need to return target-specific instances of these classes. Both\nfiles contain detailed information on the invariants that Cascade imposes on\nthe implementation of a ```Core``` and the functionality provided by an\n```Interface```. Briefly, a ```Core``` is responsible for implementing support\nfor the Cascade runtime ABI. This ABI is the mechanism by which Cascade\norchestrates the communication and computation necessary to satisfy the\nsemantics of Verilog while at the same time providing support for the\njust-in-time features described above. \n\nOnce you've finished implementing your compiler, you'll need to register it by\nadding a few lines of code to ```src/cascade/cascade.cc```.\n```c++\nCascade::Cascade() : eval_(this), iostream(\u0026sb_), sb_() {\n  // ...\n  runtime_.get_compiler()-\u003eset(\"sw\", new SwCompiler());\n  runtime_.get_compiler()-\u003eset(\"my_backend\", new MyBackendCompiler());\n  // ...\n}\n```\n\nRebuild your source and... everything should just work... Happy debugging!\n\nFAQ\n====\n\n#### Flex fails during build with an error related to yyin even though I'm using version 2.6 or greater.\nSome package managers fail to update the flex header file ```FlexLexer.h``` when upgrading versions.\nLocate your copy of ```FlexLexer.h``` and look up the definition of ```yyFlexLexer::yyin```. If \nthis variable has type ```std::istream*```, your file is out of date and you will need to patch it. \nThe current version of this file, which should have been installed can be found in Flex's top-level \n```src/``` directory.\n\n\n#### Cascade emits strange warnings whenever I declare a module.\nModule declarations are typechecked in the global scope, separate from the rest\nof your program. While this allows Cascade to catch many errors at\ndeclaration-time, there are some properties of Verilog programs which can only\nbe verified at instantiation-time. If Cascade emits a warning, it is generally\nbecause it cannot statically prove that the module you declared will\ninstantiate correctly in every possible program context.  \n\n#### Why does Cascade warn that x is undeclared when I declare Foo, but not when I instantiate it (Part 1)?\n```verilog\nlocalparam x = 0;\nmodule Foo();\n  wire q = x;\nendmodule\nFoo f();\n```\nThe local parameter ```x``` was declared in the root module, and the module\n```Foo``` was declared in its own scope. In general, there is no way for\nCascade to guarantee that you will instantiate ```Foo``` in a context where all\nof its declaration-time unresolved variables will be resolvable. In this case,\nit is statically provable, but Cascade doesn't know how to do so. When\n```Foo``` is instantiated, Cascade can verify that there is a variable named\n```p``` which is reachable from the scope in which ```f``` appears. No further\nwarnings or errors are necessary. Here is a more general example:\n```verilog\nmodule Foo();\n  assign x.y.z = 1;\nendmodule\n\n// ...\nbegin : x\n  begin : y\n    reg z;\n  end\nend\n// ...\nFoo f(); // This instantiation will succeed because a variable named z\n         // is reachable through the hierarchical name x.y.z from f.\n         \n// ...\nbegin : q\n  reg r;\nend\n// ...\nFoo f(); // This instantiation will fail because the only variable\n         // reachable from f is q.r.\n```\n\n#### Why does Cascade warn that x is undeclared when I declare Foo, but not when I instantiate it (Part 2)?\n```verilog\nmodule #(parameter N) Foo();\n  genvar i;\n  for (i = 0; i \u003c N; i=i+1) begin : GEN\n    reg x;\n  end\n  wire q = GEN[5].x;\nendmodule\nFoo#(8) f();\n```\nThe register ```x``` was declared in a loop generate construct with bounds\ndetermined by a parameter. In general, there is no way for Cascade to guarantee\nthat you will instantiate ```Foo``` with a parameter binding such that all of\nits declaration-time unresolved variables are resolvable. When ```Foo``` is\ninstantiated with ```N=8```, Cascade can verify that there is a variable named\n```GEN[5].x```. No further warnings or errors are necessary.\n\nMore generally, Cascade will defer typechecking for code that appears inside of\ngenerate constructs until instantiation-time.\n\n#### I get it, but it seems like there's something about pretty much every module declaration that Cascade can't prove.\nThe truth hurts. Remember that if you'd like to disable warnings you can type.\n```\n$ cascade --disable_warning\n```\n","funding_links":[],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvmware-archive%2Fcascade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvmware-archive%2Fcascade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvmware-archive%2Fcascade/lists"}