From a701f99fd6fc5eb21c138312dc93b581329bf50b Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Sun, 22 Sep 2024 18:56:26 -0700 Subject: [PATCH 1/3] add repeat() --- crates/fayalite/src/expr.rs | 17 ++++++++++++++++- crates/fayalite/src/prelude.rs | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/fayalite/src/expr.rs b/crates/fayalite/src/expr.rs index 644d058..fa50852 100644 --- a/crates/fayalite/src/expr.rs +++ b/crates/fayalite/src/expr.rs @@ -9,7 +9,7 @@ use crate::{ ops::ExprCastTo, target::{GetTarget, Target}, }, - int::{Bool, DynSize, IntType, SIntType, SIntValue, Size, UInt, UIntType, UIntValue}, + int::{Bool, DynSize, IntType, SIntType, SIntValue, Size, SizeType, UInt, UIntType, UIntValue}, intern::{Intern, Interned}, memory::{DynPortType, MemPort, PortType}, module::{ @@ -720,3 +720,18 @@ impl MakeUninitExpr for T { ops::Uninit::new(self).to_expr() } } + +pub fn repeat( + element: impl ToExpr, + len: L, +) -> Expr> { + let element = element.to_expr(); + let canonical_element = Expr::canonical(element); + ops::ArrayLiteral::new( + Expr::ty(element), + std::iter::repeat(canonical_element) + .take(L::Size::as_usize(len)) + .collect(), + ) + .to_expr() +} diff --git a/crates/fayalite/src/prelude.rs b/crates/fayalite/src/prelude.rs index 5dc503e..7b7d718 100644 --- a/crates/fayalite/src/prelude.rs +++ b/crates/fayalite/src/prelude.rs @@ -7,7 +7,7 @@ pub use crate::{ clock::{Clock, ClockDomain, ToClock}, enum_::{HdlNone, HdlOption, HdlSome}, expr::{ - CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr, + repeat, CastBitsTo, CastTo, CastToBits, Expr, HdlPartialEq, HdlPartialOrd, MakeUninitExpr, ReduceBits, ToExpr, }, hdl, hdl_module, From f6146048d1a6fa4c06db8c0289794481c36f9a01 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Sun, 22 Sep 2024 18:57:30 -0700 Subject: [PATCH 2/3] add memory::splat_mask to generate mask types from a Bool --- crates/fayalite/src/memory.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/fayalite/src/memory.rs b/crates/fayalite/src/memory.rs index e6bbea5..1762f57 100644 --- a/crates/fayalite/src/memory.rs +++ b/crates/fayalite/src/memory.rs @@ -7,7 +7,7 @@ use crate::{ array::{Array, ArrayType}, bundle::{Bundle, BundleType}, clock::Clock, - expr::{Expr, Flow, ToExpr, ToLiteralBits}, + expr::{ops::BundleLiteral, repeat, Expr, Flow, ToExpr, ToLiteralBits}, hdl, int::{Bool, DynSize, Size, UInt, UIntType}, intern::{Intern, Interned}, @@ -1050,3 +1050,32 @@ impl MemBuilder { .extend(annotations.into_annotations()); } } + +pub fn splat_mask(ty: T, value: Expr) -> Expr> { + let canonical_ty = ty.canonical(); + match canonical_ty { + CanonicalType::UInt(_) + | CanonicalType::SInt(_) + | CanonicalType::Bool(_) + | CanonicalType::AsyncReset(_) + | CanonicalType::SyncReset(_) + | CanonicalType::Reset(_) + | CanonicalType::Clock(_) + | CanonicalType::Enum(_) => Expr::from_canonical(Expr::canonical(value)), + CanonicalType::Array(array) => Expr::from_canonical(Expr::canonical(repeat( + splat_mask(array.element(), value), + array.len(), + ))), + CanonicalType::Bundle(bundle) => Expr::from_canonical(Expr::canonical( + BundleLiteral::new( + bundle.mask_type(), + bundle + .fields() + .iter() + .map(|field| splat_mask(field.ty, value)) + .collect(), + ) + .to_expr(), + )), + } +} From 716c65edcd421fa3a28d271ec647188331c2d52a Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Sun, 22 Sep 2024 18:59:12 -0700 Subject: [PATCH 3/3] add WIP version of queue() --- crates/fayalite/src/util/ready_valid.rs | 130 +++++++++++++++++++++++- 1 file changed, 129 insertions(+), 1 deletion(-) diff --git a/crates/fayalite/src/util/ready_valid.rs b/crates/fayalite/src/util/ready_valid.rs index ec761c2..94154c9 100644 --- a/crates/fayalite/src/util/ready_valid.rs +++ b/crates/fayalite/src/util/ready_valid.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use crate::prelude::*; +use crate::{memory::splat_mask, prelude::*}; +use std::num::NonZeroUsize; #[hdl] pub struct ReadyValid { @@ -34,3 +35,130 @@ impl ReadyValid { mapped } } + +// TODO: needs testing +#[hdl_module] +pub fn queue( + ty: T, + capacity: NonZeroUsize, + inp_ready_is_comb: bool, + out_valid_is_comb: bool, +) { + let count_ty = UInt::range_inclusive(0..=capacity.get()); + let index_ty = UInt::range(0..capacity.get()); + + #[hdl] + let cd: ClockDomain = m.input(); + #[hdl] + let inp: ReadyValid = m.input(ReadyValid[ty]); + #[hdl] + let out: ReadyValid = m.output(ReadyValid[ty]); + #[hdl] + let count: UInt = m.output(count_ty); + + #[hdl] + let inp_index = reg_builder().clock_domain(cd).reset(0.cast_to(index_ty)); + #[hdl] + let out_index = reg_builder().clock_domain(cd).reset(0.cast_to(index_ty)); + #[hdl] + let maybe_full = reg_builder().clock_domain(cd).reset(false); + + #[hdl] + let mut mem = memory(ty); + mem.depth(capacity.get()); + let read_port = mem.new_read_port(); + let write_port = mem.new_write_port(); + + #[hdl] + let inp_fire: Bool = wire(); + connect(inp_fire, ReadyValid::fire(inp)); + #[hdl] + let out_fire: Bool = wire(); + connect(out_fire, ReadyValid::fire(out)); + #[hdl] + let indexes_equal: Bool = wire(); + connect(indexes_equal, inp_index.cmp_eq(out_index)); + #[hdl] + let empty: Bool = wire(); + connect(empty, indexes_equal & !maybe_full); + #[hdl] + let full: Bool = wire(); + connect(full, indexes_equal & maybe_full); + + connect(read_port.addr, out_index); + connect(read_port.en, true); + connect(read_port.clk, cd.clk); + connect(write_port.addr, inp_index); + connect(write_port.en, inp_fire); + connect(write_port.clk, cd.clk); + connect(write_port.data, HdlOption::unwrap_or(inp.data, ty.uninit())); + connect(write_port.mask, splat_mask(ty, true.to_expr())); + + connect(inp.ready, !full); + if inp_ready_is_comb { + #[hdl] + if out.ready { + connect(inp.ready, true); + } + } + + #[hdl] + if !empty { + connect(out.data, HdlSome(read_port.data)); + } else { + if out_valid_is_comb { + connect(out.data, inp.data); + } else { + connect(out.data, HdlOption[ty].HdlNone()); + } + } + + #[hdl] + if inp_fire.cmp_ne(out_fire) { + connect(maybe_full, inp_fire); + } + + #[hdl] + if inp_fire { + #[hdl] + if inp_index.cmp_eq(capacity) { + connect_any(inp_index, 0_hdl_u0); + } else { + connect_any(inp_index, inp_index + 1_hdl_u1); + } + } + + #[hdl] + if out_fire { + #[hdl] + if out_index.cmp_eq(capacity) { + connect_any(out_index, 0_hdl_u0); + } else { + connect_any(out_index, out_index + 1_hdl_u1); + } + } + + #[hdl] + if indexes_equal { + connect( + count, + maybe_full.cast_to_static::>() << (count_ty.width() - 1), + ); + } else { + if capacity.is_power_of_two() { + debug_assert_eq!(count_ty.width(), index_ty.width() + 1); + #[hdl] + let count_lower = wire(index_ty); + connect(count_lower, (inp_index - out_index).cast_to(index_ty)); // wrap + connect(count, count_lower.cast_to(count_ty)); + } else { + debug_assert_eq!(count_ty.width(), index_ty.width()); + #[hdl] + if inp_index.cmp_lt(out_index) { + connect(count, inp_index + capacity - out_index); + } else { + connect(count, inp_index - out_index); + } + } + } +}