C⏚ v2.0.0Updated 2026-05-12·Getting started

Quick tutorial

This tutorial walks through the canonical C⏚ workflow end to end:

  1. Write a 4-bit counter task in .cg.
  2. Wrap it in a test network with an asserting monitor.
  3. Run the bytecode simulator and watch assertions pass.
  4. Generate synthesizable Verilog from the same source.

The steps below assume a current toolchain release and the standard cg-language-server.jar / VS Code extension workflow.

Prerequisites

You need one of:

  • VS Code with the Neosyn C⏚ Language extension installed.
  • A standalone cg-language-server.jar (Java 17+) - built from releng/lsp-server or downloaded from a release.

The VS Code path is faster for iteration; the standalone JAR is useful for CI and headless setups.

You also need a project layout the compiler can resolve. For the example below, create this folder structure first:

my-project/
  src/
    com/
      example/

Because the files declare package com.example;, they should live under com/example/.

See Project layout for the general rules behind this example.

Step 1 - Write the counter

Create src/com/example/Counter.cg:

package com.example;
 
task Counter {
  out push u4 count;
 
  u4 value = 0;
 
  void loop() {
    count.write(value);
    value = value + 1;
  }
}

Things to notice:

  • The task has a single output port count of type u4 (4-bit unsigned). The push qualifier means writes carry a one-cycle valid pulse - consumers can block waiting for fresh data.
  • value is a state variable at the task level - it persists across cycles. Initialized to 0.
  • loop() runs once per cycle: write the current value, then increment.

Step 2 - Add a test network with a monitor

The bytecode simulator runs whichever network you point it at, not the task directly. The canonical pattern is a thin test network that instantiates the design under test (DUT) plus a monitor inner task that asserts what we expect cycle by cycle.

Create src/com/example/Counter_test.cg:

package com.example;
 
network Counter_test {
  import com.example.Counter;
 
  properties {
    test: { terminate: "monitor.finished" }
  }
 
  dut = new Counter();
 
  monitor = new task {
    bool finished;
 
    void setup() {
      for (u4 expected = 0; expected < 8; expected++) {
        u4 got = dut.count.read();
        print("cycle ", expected, " count = ", got);
        assert(got == expected);
      }
      finished = true;
    }
  };
}

The key bits:

  • properties { test: { terminate: "monitor.finished" } } tells the simulator to keep running until monitor.finished becomes true.
  • The monitor is an inner task - anonymous, defined inline. It has a single state variable finished (a bool).
  • In setup(), the monitor reads dut.count repeatedly, prints each value, and asserts it equals what we expect. After the loop, it sets finished = true, which terminates the simulation.

Step 3 - Run the bytecode simulator

From VS Code

Open Counter_test.cg in the editor, then either:

  • Run the Neosyn: Fast Simulation (Bytecode) command from the command palette, or
  • Click the play-icon Fast Simulation (Bytecode) action in the editor title bar.

The console pane shows the cycle-by-cycle output. Integers print as hex (0x...) by default - see Bytecode simulator → Print and assertions:

cycle 0x0 count = 0x0
cycle 0x1 count = 0x1
cycle 0x2 count = 0x2
cycle 0x3 count = 0x3
cycle 0x4 count = 0x4
cycle 0x5 count = 0x5
cycle 0x6 count = 0x6
cycle 0x7 count = 0x7
Simulation completed successfully.

If any assert fails, the simulation stops with a diagnostic at the offending cycle.

From the command line

java -jar cg-language-server.jar simulate path/to/Counter_test.cg

If your .cg file declares multiple top-level entities and the simulator can't pick one automatically, name it explicitly:

java -jar cg-language-server.jar simulate path/to/Counter_test.cg \
  --entity Counter_test

The short alias sim also works:

java -jar cg-language-server.jar sim path/to/Counter_test.cg

Step 4 - Inspect the waveform

The simulation drops a VCD file at the project root (Counter_test.vcd by default - named after the top-level entity, placed alongside src/ and verilog-gen/), capturing every port and state variable at every cycle.

  • VS Code: run the Neosyn: Open Waveform command, or open the .vcd directly with the WaveTrace extension.
  • GTKWave / Surfer: open the file with any standalone VCD viewer.

For our counter you'll see count.data step through 0..7 and count.valid pulse high every cycle.

Step 5 - Generate Verilog

The same .cg source compiles to synthesizable HDL.

From VS Code

Run Neosyn: Generate HDL from the command palette. Output lands in verilog-gen/ at the project root (next to src/).

From the command line

java -jar cg-language-server.jar generate path/to/Counter.cg

By default this produces Verilog. To target VHDL instead:

java -jar cg-language-server.jar generate path/to/Counter.cg --target vhdl

To choose a specific output directory:

java -jar cg-language-server.jar generate path/to/project --output build/hdl

The generated HDL is plain text intended for normal downstream FPGA toolchains. Exact synthesis results still depend on the backend, target device, and the constructs used in your design.

Step 6 - What the generated Verilog gives you

The output of step 5 is synthesizable RTL for the DUT itself - nothing more. The monitor's print() and assert() calls live only in the bytecode simulator; they have no synthesizable equivalent and don't appear in the generated .v files.

What you can do with the generated Verilog:

  • Hand it to your FPGA toolchain (Vivado, Quartus, Yosys, etc.) for synthesis and place-and-route - see FPGA integration.
  • Drive the DUT from a hand-written Verilog testbench if you need an HDL-level cross-check beyond bytecode coverage - see Cross-check against HDL for when and how.

What you cannot do is replay the inline-monitor pattern through iverilog and expect the same printouts. The monitor is a bytecode-side construct. The bytecode simulator is the canonical correctness check; the Verilog backend exists to feed downstream synthesis tools.

What you just exercised

LayerToolOutput
Sourcetext editor / VS CodeCounter.cg, Counter_test.cg
Bytecode simcg-language-server.jar simulateconsole output + Counter_test.vcd
HDL gencg-language-server.jar generateverilog-gen/com/example/Counter.v (DUT only)

The same source flows through both layers, but they serve different purposes: bytecode for fast correctness loops, Verilog for synthesis.

Where next

  • Bytecode simulator - full reference on monitors, the test property, VCD output.
  • Concepts - bit-accurate types, cycle-by-cycle execution, determinism. The next layer of mental model.
  • Tasks - full task semantics including cycle breaks, setup / loop, external tasks.
  • Networks - wiring instances together for non-trivial designs.
  • Standard library - FIFOs, RAMs, clock-domain synchronizers.