logo Spade Playground Docs Blog Gitlab icon Gitlab Discord community icon Discord community

Spade:一种受现代软件语言启发的硬件描述语言

在浏览器中尝试 Spade 📚 文档

// 一个支持 Add, Sub, Set 和 Jump 的三级流水线 CPU
pipeline(3) cpu(...) -> Option<int<32>> {
let stall = stage(+1).is_jump;
let pc = inst program_counter(
      clk, rst,
      stall,
stage(execute).jump_target
    );
reg;
let insn = inst read_progmem(clk, pc);
let is_jump = is_jump(insn);
let insn = if stage(+1).is_jump {NOP} else {insn};
reg;
'execute
let (opa, opb) = inst regfile(
      clk, insn, stage(writeback).result
    );
let jump_target = match insn {
      Instruction::Jump(target) => Some(target),
_ => None;
    };
let alu_result = alu(insn, opa, opb);
reg;
'writeback
let result = match insn {
      Instruction::Add(_, _, _) => Some(alu_result),
      Instruction::Sub(_, _, _) => Some(alu_result),
      Instruction::Set(_, _) => Some(alu_result),
      Instructions::Jump(_) => None
    };
    result
}

目录

Spade

Spade 是一种新的硬件描述语言,旨在使硬件描述更容易且不易出错。它通过借鉴软件编程语言的经验,并添加对常见硬件构造的语言级别支持来实现这一点,所有这些都不会损害对所生成硬件的低级别控制。

主要特性

语言级别的流水线

流水线是 Spade 中的一等公民,使得重新计时和重新流水线化变得非常简单。reg 将代码分隔到各个阶段,这意味着您无需手动定义流水线寄存器,并且行为与物理实现分离。

当您需要更新设计以满足时序要求时,只需添加或移动 reg 语句即可。编译器足够智能,可以确定这些更改何时会影响实例化模块的时序,并告诉您在哪里更新代码以保持原始行为。

pipeline(4) X(clk: clk, a: int<32>, b: int<32>) -> int<64> {
let product = a * b;
reg * 3;
let result = f(a, product);
reg;
    result
}

对于具有反馈的更复杂的流水线(例如处理器数据路径),重新计时变得不那么简单,但是能够推理阶段中的信号而不是单个寄存器仍然非常有帮助。

类型和枚举

Spade 具有强大的类型系统,包括结构体、数组、元组和称为 enums和类型 。强大的类型系统使与外部或内部模块的互操作更容易,并且意味着您可以放心地重构代码。编译器会告诉您哪些更改会影响代码的行为。

枚举尤其重要:与 C 和 Verilog 的枚举不同,它们可以具有关联的有效载荷。

您可以使用 Option 枚举来建模可能可用或不可用的值:

enum Option<T> {
Some(val: T),
None
}

或者为什么不建模 CPU 的指令集?

enum Insn {
  Set { dreg: int<5>, val: int<32> },
  Add { dreg: int<5>, lhs: int<5>, rhs: int<5> },
  Sub { dreg: int<5>, lhs: int<5>, rhs: int<5> },
  Jump { target: int<32> }
}

编译器确保只有当值属于正确的类型时才能访问字段。例如,如果指令是 Jump,则无法访问 dreg 字段。

模式匹配

枚举与模式匹配配合得很好,模式匹配允许您检查条件并轻松地将子值绑定到变量。

您可以轻松构建一个 ALU:

fn alu(insn: Insn, rs1: int<32>, rs2: int<32>) -> int<32> {
let adder_result = match insn {
    Insn::Add(_, _, _) => rs1 + rs2,
    Insn::Sub(_, _, _) => rs1 - rs2,
    Insn::Set(_, val) => sext(val),
    Insn::Jump(_) => 0,
  };
trunc(adder_result)
}

或者选择两个值中的第一个,如果都不存在则选择 0:

let result = match (a, b) {
  (Some (x), _) => x,
  (_, Some(x)) => x,
_ => 0
}

编译器确保涵盖所有情况。例如,如果您向 Insn 类型添加新指令,它将强制您在 ALU 中处理这种情况。

类型推断

Spade 具有强大的类型推断功能,可让您获得静态类型的好处,而无需进行任何类型标注。

良好的错误消息

编译器应该是您的朋友。错误消息会为您提供尽可能多的信息

error: Match branches have incompatible type
30 +-Insn::Add(_, _, _) => rs1 + rs2,
  |            ^^^^^^^^^
  |            This branch has type int<33>
32 | Insn::Set(_, val) => val,
  |           ^^^ But this one has type int<32>
  |
  = Expected: 33 in: int<33>
  =   Got: 32 in: int<32>

糟糕的错误消息被认为是错误。请报告它们!

有用的工具

Spade 附带一套围绕该语言的出色工具

计划中的功能

还有一些计划中的功能:

使用 Spade

要开始使用,请阅读(正在进行中)spade book

要概述 Spade 是什么,请查看 OSDA 2023 的演讲。文档仍在开发中,但部分内容已在我们的 book 中提供。

Spade 处于早期阶段,因此一切都可能发生变化。您可以用它构建东西,但要为错误和缺少的功能做好准备。

了解更多

您可以选择在 Gitlab 或我们的 Discord community server 上关注开发。

出版物

要引用 Spade 本身,请使用 zenodo record

演讲

开发

Linköping University logo Linköping University logo

Spade 目前作为瑞典 Linköping UniversityDepartment of Electrical EngineeringDivision of Computer Engineering 开放源代码项目进行开发。

许可协议

Spade 编译器和其他工具在 EUPL-1.2 license 下获得许可。 Spade 标准库和本网站均已获得 MIT licenseApache license 的条款许可。

网站源代码

在 MIT 和 Apache 双重许可下获得许可。

Zola 提供支持。