日本語

Compiler - SystemVerilog Backend

Difficulty: 🟡 Intermediate
Time: 30 min

Cm can generate SystemVerilog (SV) code to run as hardware on FPGAs. Compatible with Tang Console (Gowin), Xilinx, Intel, and more.

Basic Usage

# Generate SV
cm compile --target=sv program.cm -o output.sv

# A testbench is also auto-generated
# output_tb.sv is created alongside

Port Declaration

Use #[input] / #[output] attributes to declare I/O ports.

//! platform: sv

#[input]  int a = 0;
#[input]  int b = 0;
#[output] int sum = 0;

void adder() {
    sum = a + b;
}

Generated SV:

module adder (
    input logic signed [31:0] a,
    input logic signed [31:0] b,
    output logic signed [31:0] sum
);

    // adder
    always_comb begin
        sum = a + b;
    end

endmodule

Combinational and Sequential Logic

Combinational Logic (always_comb)

Regular functions are generated as combinational logic (always_comb).

//! platform: sv

#[input]  int a = 0;
#[input]  int b = 0;
#[input]  int c = 0;
#[output] int out = 0;

void max3() {
    if (a > b) {
        if (a > c) { out = a; } else { out = c; }
    } else {
        if (b > c) { out = b; } else { out = c; }
    }
}

Sequential Logic (always_ff)

Using posedge / negedge type parameters generates always_ff blocks.

//! platform: sv

#[output] uint counter = 0;
#[output] bool led = false;

void blink(posedge clk, bool rst) {
    if (rst) {
        counter = 0;
        led = false;
    } else {
        if (counter == 49999999) {
            counter = 0;
            led = !led;
        } else {
            counter = counter + 1;
        }
    }
}

Generated SV:

always_ff @(posedge clk) begin
    if (rst) begin
        counter <= 32'd0;
        led <= 1'b0;
    end else begin
        if (counter == 32'd49999999) begin
            counter <= 32'd0;
            led <= !led;
        end else begin
            counter <= counter + 32'd1;
        end
    end
end

SV-Specific Types

Cm Type Description Generated SV
posedge Rising edge always_ff @(posedge ...)
negedge Falling edge always_ff @(negedge ...)
wire Wire wire
reg Register reg

SV Width-Qualified Literals

SystemVerilog-style width-qualified literals can be written directly and are preserved in the SV output.

//! platform: sv

#[input]  utiny sel = 0;
#[output] utiny out = 0;

void literal_test() {
    if (sel == 0) {
        out = 3'b101;     // Binary: 3-bit width
    } else if (sel == 1) {
        out = 8'hFF;      // Hexadecimal: 8-bit width
    } else {
        out = 8'd170;     // Decimal: 8-bit width
    }
}
Cm Source SV Output
3'b101 3'b101
8'hFF 8'hFF
8'd170 8'd170

Cm to SV Type Mapping

Cm Type SV Bit Width SV Type
bool 1 logic
utiny 8 logic [7:0]
tiny 8 logic signed [7:0]
ushort 16 logic [15:0]
short 16 logic signed [15:0]
uint 32 logic [31:0]
int 32 logic signed [31:0]

BRAM Inference

Arrays are inferred as Block RAM (BRAM).

//! platform: sv

int memory[256];
#[input]  utiny addr = 0;
#[input]  int   wdata = 0;
#[input]  bool  we = false;
#[output] int   rdata = 0;

void bram_access(posedge clk) {
    if (we) {
        memory[addr] = wdata;
    }
    rdata = memory[addr];
}

Auto-Generated Testbench

Running cm compile --target=sv also generates a _tb.sv testbench. Verify with iverilog:

# Compile and generate testbench
cm compile --target=sv program.cm -o output.sv

# Run simulation
iverilog -g2012 -o sim output.sv output_tb.sv
vvp sim

Target FPGAs

Board Chip Tool
Tang Console Gowin Gowin EDA
Tang Nano 9K Gowin GW1NR-9 Gowin EDA
Arty A7 Xilinx Artix-7 Vivado
DE10-Lite Intel MAX 10 Quartus

Note: In Gowin EDA, enable SystemVerilog via Project → Configuration → Synthesis → Verilog Language.


Previous: WASM Backend
Next: Formatter


Last updated: 2026-03-09