Introduction
C⏚ is a programming language that compiles to digital hardware.
You write a sequential program. The compiler emits synthesizable Verilog or VHDL, and the same source also runs in a fast cycle-accurate simulator. There is no hand-rolled FSM, no blocking versus non-blocking assignment, no signal-strength bookkeeping. What you write is what the synthesizer gets.
This chapter gives you the mental model. The Quick tutorial walks you through building a design end to end.
A program that becomes a chip
Here is a complete 9-line C⏚ task, and the Verilog the compiler emits from it:
The left column is what you write. The right column is what your FPGA toolchain consumes.
Nothing is hidden. The state variable value becomes a Verilog
reg. The count.write(value) call becomes a registered output
with a paired count_valid strobe. The cycle break between
iterations of loop() becomes a named FSM block in the always
process. If you can read RTL, you can audit what the compiler did.
The mental model
Digital hardware is built from two ingredients on a shared clock:
- Registers capture a value on the clock's rising edge.
- Combinational logic computes the next value from the current one.
A C⏚ task maps directly onto this picture. Every state variable
becomes a register. Every expression between reads and writes
becomes combinational logic. One pass through loop() is one
clock cycle.
Tasks communicate only through ports. State variables are private. A keyword on each port declaration selects the handshake:
push- registered output with a valid strobe.stream- push plus ready/valid back-pressure.confirm- push plus consumer acknowledgement.- (bare) - combinational wire, no handshake.
See Declarations for the full reference.
Networks compose tasks into hierarchies. They contain no
behaviour of their own, only structural wiring. The Intel-8088
reference CPU is a C⏚ network with two top-level instances -
ExecutionUnit and BusInterfaceUnit - wired through real
push and stream ports.
That is the whole model: tasks, networks, ports, on a clock.
One source, two simulations
The C⏚ compiler emits the same design two ways from the same intermediate representation:
JVM bytecode is the fast path. Every task becomes a Java
method, every network becomes a clock-scheduled class. The
resulting .class files run cycle-accurately on the JVM. Actual
throughput depends on the design shape, host machine, JVM, and
whether waveform generation is enabled.
Verilog and VHDL are the synthesis path. The compiler emits RTL designed to be readable and synthesizer-friendly - one module per task, one per network. Exact downstream requirements still depend on the target toolchain and device family.
Both outputs read the same intermediate representation. Behaviour in the fast simulator matches behaviour in synthesis.
For higher-confidence verification, you run the same testbench through both paths. The bytecode trace and the HDL trace should agree cycle for cycle. When they disagree, it is a compiler bug or a design ambiguity worth resolving. Either way, you find it before silicon.
The Intel-8088 reference IP is used internally as a realistic regression target. It exercises both bytecode simulation and HDL cross-checking, and it is a good example of the workflow at non-trivial scale.
Next: the Quick tutorial builds a Counter end to end. The Bytecode simulator chapter explains how the fast simulator is wired up, and Tasks and Networks cover the language constructs in depth.