Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supporting external writes to registers #1875

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ calyx-ir = { path = "calyx-ir", version = "0.6.1" }
calyx-frontend = { path = "calyx-frontend", version = "0.6.1" }
calyx-opt = { path = "calyx-opt", version = "0.6.1" }
calyx-backend = { path = "calyx-backend", version = "0.6.1" }
calyx-stdlib = { path = "calyx-stdlib", version = "0.6.1" }

[workspace.dependencies.petgraph]
version = "0.6"
Expand Down
1 change: 1 addition & 0 deletions calyx-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ smallvec.workspace = true
calyx-utils.workspace = true
calyx-frontend.workspace = true
calyx-ir.workspace = true
calyx-stdlib.workspace = true

csv = { version = "1.1", optional = true }
vast = "0.3.1"
Expand Down
57 changes: 25 additions & 32 deletions calyx-backend/src/verilog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use crate::traits::Backend;
use calyx_ir::{self as ir, Control, FlatGuard, Group, Guard, GuardRef, RRC};
use calyx_stdlib as primitives;
use calyx_utils::{CalyxResult, Error, OutputFile};
use ir::Nothing;
use itertools::Itertools;
Expand All @@ -18,21 +19,6 @@ use vast::v17::ast as v;
#[derive(Default)]
pub struct VerilogBackend;

// input string should be the cell type name of a memory cell. In other words one
// of "seq/std_mem_d_1/2/3/4". Becase we define seq_mem_d2/3/4 in terms of seq_mem_d1
// we need another layer of memory access to get the actual memory array in verilog
// for these mem types.
// In other words, for memories not defined in terms of another memory, we can just use
// "mem" to access them. But for memories defined in terms of another memory,
// which are seq_mem_d2/3/4, we need "mem.mem" to access them.
fn get_mem_str(mem_type: &str) -> &str {
if mem_type.contains("d1") || mem_type.contains("std_mem") {
"mem"
} else {
"mem.mem"
}
}

/// Checks to make sure that there are no holes being
/// used in a guard.
fn validate_guard(guard: &ir::Guard<Nothing>) -> bool {
Expand Down Expand Up @@ -778,22 +764,29 @@ fn memory_read_write(comp: &ir::Component) -> Vec<v::Stmt> {
.cells
.iter()
.filter_map(|cell| {
let is_external = cell.borrow().get_attribute(ir::BoolAttr::External).is_some();
if is_external
&& cell
.borrow()
.type_name()
// HACK: Check if the name of the primitive contains the string "mem"
.map(|proto| proto.id.as_str().contains("mem"))
.unwrap_or_default()
{
Some((
cell.borrow().name().id,
cell.borrow().type_name().unwrap_or_else(|| unreachable!("tried to add a memory cell but there was no type name")),
))
} else {
None
let cell = cell.borrow();
if !cell.has_attribute(ir::BoolAttr::External) {
return None;
}
let loadable = cell
.type_name()
.map(|n| primitives::is_loadable(n.id.as_str()))
.unwrap_or_default();
if !loadable {
log::warn!(
"Cell {} is marked as external but is not loadable",
cell.name().id
);
return None;
}
Some((
cell.name().id,
cell.type_name().unwrap_or_else(|| {
unreachable!(
"tried to add a memory cell but there was no type name"
)
}),
))
})
.collect_vec();

Expand Down Expand Up @@ -827,7 +820,7 @@ fn memory_read_write(comp: &ir::Component) -> Vec<v::Stmt> {
)));

memories.iter().for_each(|(name, mem_type)| {
let mem_access_str = get_mem_str(mem_type.id.as_str());
let mem_access_str = primitives::load_path(mem_type.id.as_str());
initial_block.add_seq(v::Sequential::new_seqexpr(v::Expr::new_call(
"$readmemh",
vec![
Expand All @@ -844,7 +837,7 @@ fn memory_read_write(comp: &ir::Component) -> Vec<v::Stmt> {

let mut final_block = v::ParallelProcess::new_final();
memories.iter().for_each(|(name, mem_type)| {
let mem_access_str = get_mem_str(mem_type.id.as_str());
let mem_access_str = primitives::load_path(mem_type.id.as_str());

final_block.add_seq(v::Sequential::new_seqexpr(v::Expr::new_call(
"$writememh",
Expand Down
5 changes: 5 additions & 0 deletions calyx-ir/src/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,11 @@ impl Cell {
self.attributes.get(attr.into())
}

/// Return true if this cell has the given attribute.
pub fn has_attribute<A: Into<Attribute>>(&self, attr: A) -> bool {
self.attributes.has(attr.into())
}

/// Add a new attribute to the group.
pub fn add_attribute<A: Into<Attribute>>(&mut self, attr: A, value: u64) {
self.attributes.insert(attr.into(), value);
Expand Down
5 changes: 5 additions & 0 deletions calyx-stdlib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
mod memories;
mod primitives;

pub use memories::{
is_loadable, load_path, SEQ_MEM_D1, SEQ_MEM_D2, SEQ_MEM_D3, SEQ_MEM_D4,
STD_MEM_D1, STD_MEM_D2, STD_MEM_D3, STD_MEM_D4, STD_REG,
};
pub use primitives::{COMPILE_LIB, KNOWN_LIBS};
44 changes: 44 additions & 0 deletions calyx-stdlib/src/memories.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! Verilog-level names for the primitives

/// Register
pub const STD_REG: &str = "std_reg";

// Memories
pub const STD_MEM_D1: &str = "std_mem_d1";
pub const STD_MEM_D2: &str = "std_mem_d2";
pub const STD_MEM_D3: &str = "std_mem_d3";
pub const STD_MEM_D4: &str = "std_mem_d4";

// Sequential Memories
pub const SEQ_MEM_D1: &str = "seq_mem_d1";
pub const SEQ_MEM_D2: &str = "seq_mem_d2";
pub const SEQ_MEM_D3: &str = "seq_mem_d3";
pub const SEQ_MEM_D4: &str = "seq_mem_d4";

/// The primitive supports loading input value from a file using `readmemh` and
/// `writememh` calls in Verilog.
pub fn is_loadable(type_name: &str) -> bool {
matches!(
type_name,
STD_REG
| STD_MEM_D1
| STD_MEM_D2
| STD_MEM_D3
| STD_MEM_D4
| SEQ_MEM_D1
| SEQ_MEM_D2
| SEQ_MEM_D3
| SEQ_MEM_D4
)
}

/// Verilog module path to load values into.
pub fn load_path(type_name: &str) -> &str {
match type_name {
STD_REG => "mem",
STD_MEM_D1 | STD_MEM_D2 | STD_MEM_D3 | STD_MEM_D4 => "mem",
SEQ_MEM_D1 => "mem",
SEQ_MEM_D2 | SEQ_MEM_D3 | SEQ_MEM_D4 => "mem.mem",
_ => unreachable!("Unknown loadable primitive: {type_name}"),
}
}
6 changes: 4 additions & 2 deletions primitives/compile.futil
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ primitive std_reg<"state_share"=1>[WIDTH](
)
// ANCHOR_END: std_reg_def
{
logic [WIDTH-1:0] mem;
assign out = mem;
always_ff @(posedge clk) begin
if (reset) begin
out <= 0;
mem <= 0;
done <= 0;
end else if (write_en) begin
out <= in;
mem <= in;
done <= 1'd1;
end else done <= 1'd0;
end
Expand Down
Loading