1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
//! Abstract Syntax Tree for Calyx
use super::parser;
use crate::{Attributes, PortDef, Primitive};
use atty::Stream;
use calyx_utils::{CalyxResult, Error, GPosIdx, Id, PosString};
use std::{num::NonZeroU64, path::PathBuf};
/// Corresponds to an individual Calyx file.
#[derive(Debug)]
pub struct NamespaceDef {
/// Path to extern files.
pub imports: Vec<PosString>,
/// List of component definitions.
pub components: Vec<ComponentDef>,
/// Extern statements and any primitive declarations in them.
pub externs: Vec<(Option<PosString>, Vec<Primitive>)>,
/// Optional opaque metadata
pub metadata: Option<String>,
}
impl NamespaceDef {
/// Construct a namespace from a file or the input stream.
/// If no file is provided, the input stream must be a TTY.
pub fn construct(file: &Option<PathBuf>) -> CalyxResult<Self> {
match file {
Some(file) => parser::CalyxParser::parse_file(file),
None => {
if atty::isnt(Stream::Stdin) {
parser::CalyxParser::parse(std::io::stdin())
} else {
Err(Error::invalid_file(
"No file provided and terminal not a TTY".to_string(),
))
}
}
}
}
/// Construct a namespace from a definition using a string.
pub fn construct_from_str(inp: &str) -> CalyxResult<Self> {
parser::CalyxParser::parse(inp.as_bytes())
}
}
/// AST statement for defining components.
#[derive(Debug)]
pub struct ComponentDef {
/// Name of the component.
pub name: Id,
/// Defines input and output ports along with their attributes.
pub signature: Vec<PortDef<u64>>,
/// List of instantiated sub-components
pub cells: Vec<Cell>,
/// List of groups
pub groups: Vec<Group>,
/// List of StaticGroups
pub static_groups: Vec<StaticGroup>,
/// List of continuous assignments
pub continuous_assignments: Vec<Wire>,
/// Single control statement for this component.
pub control: Control,
/// Attributes attached to this component
pub attributes: Attributes,
/// True iff this is a combinational component
pub is_comb: bool,
/// (Optional) latency of component, if it is static
pub latency: Option<NonZeroU64>,
}
impl ComponentDef {
pub fn new<S>(
name: S,
is_comb: bool,
latency: Option<NonZeroU64>,
signature: Vec<PortDef<u64>>,
) -> Self
where
S: Into<Id>,
{
Self {
name: name.into(),
signature,
cells: Vec::new(),
groups: Vec::new(),
static_groups: Vec::new(),
continuous_assignments: Vec::new(),
control: Control::empty(),
attributes: Attributes::default(),
is_comb,
latency,
}
}
}
/// Statement that refers to a port on a subcomponent.
/// This is distinct from a `Portdef` which defines a port.
#[derive(Debug)]
pub enum Port {
/// Refers to the port named `port` on the subcomponent
/// `component`.
Comp { component: Id, port: Id },
/// Refers to the port named `port` on the component
/// currently being defined.
This { port: Id },
/// `group[name]` parses into `Hole { group, name }`
/// and is a hole named `name` on group `group`
Hole { group: Id, name: Id },
}
// ===================================
// AST for wire guard expressions
// ===================================
#[derive(Debug)]
pub enum NumType {
Decimal,
Binary,
Octal,
Hex,
}
/// Custom bitwidth numbers
#[derive(Debug)]
pub struct BitNum {
pub width: u64,
pub num_type: NumType,
pub val: u64,
pub span: GPosIdx,
}
/// Atomic operations used in guard conditions and RHS of the
/// guarded assignments.
#[derive(Debug)]
pub enum Atom {
/// Accessing a particular port on a component.
Port(Port),
/// A constant.
Num(BitNum),
}
/// The AST for GuardExprs
#[derive(Debug)]
pub enum GuardExpr {
// Logical operations
And(Box<GuardExpr>, Box<GuardExpr>),
Or(Box<GuardExpr>, Box<GuardExpr>),
Not(Box<GuardExpr>),
CompOp(CompGuard),
Atom(Atom),
}
/// Guard Comparison Type
pub type CompGuard = (GuardComp, Atom, Atom);
/// The AST for StaticGuardExprs
#[derive(Debug)]
pub enum StaticGuardExpr {
And(Box<StaticGuardExpr>, Box<StaticGuardExpr>),
Or(Box<StaticGuardExpr>, Box<StaticGuardExpr>),
Not(Box<StaticGuardExpr>),
CompOp(CompGuard),
Atom(Atom),
StaticInfo((u64, u64)),
}
/// Possible comparison operators for guards.
#[derive(Debug)]
pub enum GuardComp {
Eq,
Neq,
Gt,
Lt,
Geq,
Leq,
}
/// Guards `expr` using the optional guard condition `guard`.
#[derive(Debug)]
pub struct Guard {
pub guard: Option<GuardExpr>,
pub expr: Atom,
}
/// Guards `expr` using the optional guard condition `guard`.
#[derive(Debug)]
pub struct StaticGuard {
pub guard: Option<StaticGuardExpr>,
pub expr: Atom,
}
// ===================================
// Data definitions for Structure
// ===================================
/// Prototype of the cell definition
#[derive(Debug)]
pub struct Proto {
/// Name of the primitive.
pub name: Id,
/// Parameter binding for primitives
pub params: Vec<u64>,
}
/// The Cell AST nodes.
#[derive(Debug)]
pub struct Cell {
/// Name of the cell.
pub name: Id,
/// Name of the prototype this cell was built from.
pub prototype: Proto,
/// Attributes attached to this cell definition
pub attributes: Attributes,
/// Whether this cell is external
pub reference: bool,
}
/// Methods for constructing the structure AST nodes.
impl Cell {
/// Constructs a primitive cell instantiation.
pub fn from(
name: Id,
proto: Id,
params: Vec<u64>,
attributes: Attributes,
reference: bool,
) -> Cell {
Cell {
name,
prototype: Proto {
name: proto,
params,
},
attributes,
reference,
}
}
}
#[derive(Debug)]
pub struct Group {
pub name: Id,
pub wires: Vec<Wire>,
pub attributes: Attributes,
pub is_comb: bool,
}
#[derive(Debug)]
pub struct StaticGroup {
pub name: Id,
pub wires: Vec<StaticWire>,
pub attributes: Attributes,
pub latency: NonZeroU64,
}
/// Data for the `->` structure statement.
#[derive(Debug)]
pub struct Wire {
/// Source of the wire.
pub src: Guard,
/// Guarded destinations of the wire.
pub dest: Port,
/// Attributes for this assignment
pub attributes: Attributes,
}
/// Data for the `->` structure statement.
#[derive(Debug)]
pub struct StaticWire {
/// Source of the wire.
pub src: StaticGuard,
/// Guarded destinations of the wire.
pub dest: Port,
/// Attributes for this assignment
pub attributes: Attributes,
}
/// Control AST nodes.
/// Since enables and static enables are indistinguishable to the AST, there
/// is single Control Enum for both Static and Dynamic Control
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub enum Control {
/// Represents sequential composition of control statements.
Seq {
/// List of `Control` statements to run in sequence.
stmts: Vec<Control>,
/// Attributes
attributes: Attributes,
},
/// Represents parallel composition of control statements.
Par {
/// List of `Control` statements to run in sequence.
stmts: Vec<Control>,
/// Attributes
attributes: Attributes,
},
/// Standard imperative if statement
If {
/// Port that connects the conditional check.
port: Port,
/// Modules that need to be enabled to send signal on `port`.
cond: Option<Id>,
/// Control for the true branch.
tbranch: Box<Control>,
/// Control for the true branch.
fbranch: Box<Control>,
/// Attributes
attributes: Attributes,
},
/// Standard imperative while statement
While {
/// Port that connects the conditional check.
port: Port,
/// Modules that need to be enabled to send signal on `port`.
cond: Option<Id>,
/// Control for the loop body.
body: Box<Control>,
/// Attributes
attributes: Attributes,
},
/// Static Repeat (essentially a bounded while loop w/o a condition)
Repeat {
/// Control for the true branch.
num_repeats: u64,
/// Control for the true branch.
body: Box<Control>,
/// Attributes
attributes: Attributes,
},
/// Runs the control for a list of subcomponents.
Enable {
/// Group to be enabled
comp: Id,
/// Attributes
attributes: Attributes,
},
/// Invoke component with input/output assignments.
Invoke {
/// Name of the component to be invoked.
comp: Id,
/// Input assignments
inputs: Vec<(Id, Atom)>,
/// Output assignments
outputs: Vec<(Id, Atom)>,
/// Attributes
attributes: Attributes,
/// Combinational group that may execute with this invoke.
comb_group: Option<Id>,
/// External cells that may execute with this invoke.
ref_cells: Vec<(Id, Id)>,
},
/// Invoke component with input/output assignments.
StaticInvoke {
/// Name of the component to be invoked.
comp: Id,
/// Input assignments
inputs: Vec<(Id, Atom)>,
/// Output assignments
outputs: Vec<(Id, Atom)>,
/// Attributes
attributes: Attributes,
/// External cells that may execute with this invoke.
ref_cells: Vec<(Id, Id)>,
/// Combinational group that may execute with this invoke.
comb_group: Option<Id>,
/// (optional) latency. Latency can be inferred if not given.
latency: Option<NonZeroU64>,
},
/// Control statement that does nothing.
Empty {
/// Attributes
attributes: Attributes,
},
/// Represents sequential composition of static control statements.
StaticSeq {
/// List of `Control` statements to run in sequence.
/// If not all of these stmts are static, we should error out
stmts: Vec<Control>,
/// Attributes
attributes: Attributes,
/// Optional latency for the seq
latency: Option<NonZeroU64>,
},
/// Represents parallel composition of static control statements.
StaticPar {
/// List of `Control` statements to run in sequence.
/// If not all of these stmts are static, we should error out
stmts: Vec<Control>,
/// Attributes
attributes: Attributes,
/// Optional latency for the par
latency: Option<NonZeroU64>,
},
/// Static if statement.
StaticIf {
/// Port that connects the conditional check.
port: Port,
/// Control for the true branch.
tbranch: Box<Control>,
/// Control for the true branch.
fbranch: Box<Control>,
/// Attributes
attributes: Attributes,
/// Optional latency; should be the longer of the two branches
latency: Option<NonZeroU64>,
},
/// Static Repeat (essentially a bounded while loop w/o a condition)
StaticRepeat {
/// Control for the true branch.
num_repeats: u64,
/// Control for the true branch.
body: Box<Control>,
/// Attributes
attributes: Attributes,
},
}
impl Control {
pub fn empty() -> Control {
Control::Empty {
attributes: Attributes::default(),
}
}
pub fn get_attributes(&self) -> &Attributes {
match self {
Control::Seq { attributes, .. } => attributes,
Control::Par { attributes, .. } => attributes,
Control::If { attributes, .. } => attributes,
Control::While { attributes, .. } => attributes,
Control::Repeat { attributes, .. } => attributes,
Control::Enable { attributes, .. } => attributes,
Control::Invoke { attributes, .. } => attributes,
Control::Empty { attributes, .. } => attributes,
Control::StaticSeq { attributes, .. } => attributes,
Control::StaticPar { attributes, .. } => attributes,
Control::StaticIf { attributes, .. } => attributes,
Control::StaticRepeat { attributes, .. } => attributes,
Control::StaticInvoke { attributes, .. } => attributes,
}
}
}