APS is a framework for designing Application-Specific Instruction-set Processors (ASIPs) using the CADL (Clay Architecture Description Language). It synthesizes custom processor instructions into hardware implementations via FIRRTL IR.
# Build the project
pixi run build # or cargo build
# Run tests
pixi run test # or cargo test
# Export instruction definitions to JSON
pixi run run -- -i samples/new.cadl -a rocc export
# or: cargo run --bin aps -- -i samples/new.cadl -a rocc export
# Synthesize to hardware implementation
pixi run run -- -i samples/new.cadl -a rocc synth
# or: cargo run --bin aps -- -i samples/new.cadl -a rocc synthCADL is a domain-specific language for defining custom processor instructions:
// Static variables and instances
static a: u32 = 1;
static acc: f32 = 0.0;
static arr: Instance = _instance("mem1d", 4, "f32"); // 1D memory array
static fifo: Instance = _instance("fifo", 1); // FIFO with depth 1
// Function definition (compile-time evaluated)
fn add_x_k(a: u32, b: u32, k: u32) -> (u32) {
return if (b == 0) {
a + k
} else {
add_x_k(a + k, b - 1, k)
};
}
// Instruction definition with encoding attributes
#[opcode(7'b0001011)]
#[funct7(7'b0000001)]
rtype accumulate(rs1: u5, rs2: u5, rd: u5) {
// Read from register file
let x: i32 = _irf[rs1];
let n: i32 = _irf[rs2];
// Stateful loop with initiation interval
with
i: u32 = (0, i_),
sum: u32 = (0, sum_)
do {
let sum_: u32 = sum + $u32(x);
let i_: u32 = i + 1;
} while (i < $u32(n));
// Write to instance and register file
_push(fifo, $f32(sum));
_irf[rd] = $i32(sum);
}
- Static Variables:
staticfor simple values and hardware instances - Instances: Hardware components created with
_instance(type, args...)- Memory arrays:
_instance("mem1d", size, element_type) - FIFOs:
_instance("fifo", depth) - Custom instances for specialized hardware
- Memory arrays:
- Instance Operations:
- Read:
_read(instance, index) - Write:
_write(instance, index, value) - Push:
_push(instance, value) - Pop:
_pop(instance)
- Read:
- Register File:
_irf[index]for read/write access - Memory:
_mem[addr]for global memory access - Type Casting:
$type(value)- e.g.,$u32(),$f32(),$signed() - Loops: Only canonical do-while with loop-carried variables
with var = (init, update)declares loop state[[II(n)]]annotation for pipeline initiation interval
- Arrays: Multi-dimensional with
[type; dim1; dim2]syntax - Bit Slicing:
value[high:low]extracts bit ranges
The synthesis pipeline transforms CADL code into optimized hardware:
CADL → AST → SIR → Optimized SIR → Scheduled Hardware → FIRRTL → SystemVerilog
- LALRPOP-based parser converts CADL to AST
- Type checking and semantic analysis
- Converts AST to Structured IR (SIR) with guard-based execution
- All operations have optional guards for conditional execution
- Control flow represented as regions (BasicBlocks, CanonLoops)
- Type Inference: Infers and validates types across the IR
- Function Inlining: Evaluates compile-time functions
- Simplification: Dead code elimination, constant folding, block merging
- Static Scheduling: SDC (System of Difference Constraints) algorithm
- Resource Allocation: Manages limited hardware resources
- Loop Pipelining: Modulo scheduling for optimal throughput
- Timing Analysis: Chaining-aware critical path computation
- Generates FIRRTL IR for hardware synthesis
- Integrates with Chipyard for RISC-V RoCC extensions