Compare commits
No commits in common. "190e440b3534a32572978511c9257d8fb8044bc0" and "d610858144383af52a066962dd22628482fdfa8b" have entirely different histories.
190e440b35
...
d610858144
|
@ -1,5 +0,0 @@
|
||||||
# Fayalite
|
|
||||||
|
|
||||||
Fayalite is a library for designing digital hardware -- a hardware description language (HDL) embedded in the Rust programming language. Fayalite's semantics are based on [FIRRTL] as interpreted by [LLVM CIRCT](https://circt.llvm.org/docs/Dialects/FIRRTL/FIRRTLAnnotations/).
|
|
||||||
|
|
||||||
[FIRRTL]: https://github.com/chipsalliance/firrtl-spec
|
|
|
@ -221,7 +221,6 @@ forward_fold!(syn::ExprCall => fold_expr_call);
|
||||||
forward_fold!(syn::ExprIf => fold_expr_if);
|
forward_fold!(syn::ExprIf => fold_expr_if);
|
||||||
forward_fold!(syn::ExprMatch => fold_expr_match);
|
forward_fold!(syn::ExprMatch => fold_expr_match);
|
||||||
forward_fold!(syn::ExprPath => fold_expr_path);
|
forward_fold!(syn::ExprPath => fold_expr_path);
|
||||||
forward_fold!(syn::ExprRepeat => fold_expr_repeat);
|
|
||||||
forward_fold!(syn::ExprStruct => fold_expr_struct);
|
forward_fold!(syn::ExprStruct => fold_expr_struct);
|
||||||
forward_fold!(syn::ExprTuple => fold_expr_tuple);
|
forward_fold!(syn::ExprTuple => fold_expr_tuple);
|
||||||
forward_fold!(syn::Ident => fold_ident);
|
forward_fold!(syn::Ident => fold_ident);
|
||||||
|
|
|
@ -1392,9 +1392,7 @@ impl Visitor {
|
||||||
fn process_literal(&mut self, literal: ExprLit) -> Expr {
|
fn process_literal(&mut self, literal: ExprLit) -> Expr {
|
||||||
let ExprLit { attrs, lit } = literal;
|
let ExprLit { attrs, lit } = literal;
|
||||||
match &lit {
|
match &lit {
|
||||||
Lit::Byte(lit_byte) => {
|
Lit::Byte(lit_byte) if lit_byte.suffix() == "hdl" => {
|
||||||
let trimmed_suffix = lit_byte.suffix().trim_start_matches('_');
|
|
||||||
if trimmed_suffix == "hdl" || trimmed_suffix == "hdl_u8" {
|
|
||||||
if let Some(retval) = self.process_int_literal(
|
if let Some(retval) = self.process_int_literal(
|
||||||
lit_byte.span(),
|
lit_byte.span(),
|
||||||
&lit_byte.value().to_string(),
|
&lit_byte.value().to_string(),
|
||||||
|
@ -1403,7 +1401,6 @@ impl Visitor {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Lit::Int(lit_int) => {
|
Lit::Int(lit_int) => {
|
||||||
if let Some(retval) = self.process_int_literal(
|
if let Some(retval) = self.process_int_literal(
|
||||||
lit_int.span(),
|
lit_int.span(),
|
||||||
|
@ -1518,7 +1515,6 @@ impl Fold for Visitor {
|
||||||
If => process_hdl_if,
|
If => process_hdl_if,
|
||||||
Match => process_hdl_match,
|
Match => process_hdl_match,
|
||||||
Array => process_hdl_array,
|
Array => process_hdl_array,
|
||||||
Repeat => process_hdl_repeat,
|
|
||||||
Struct => process_hdl_struct,
|
Struct => process_hdl_struct,
|
||||||
Tuple => process_hdl_tuple,
|
Tuple => process_hdl_tuple,
|
||||||
Call => process_hdl_call,
|
Call => process_hdl_call,
|
||||||
|
|
|
@ -9,8 +9,8 @@ use syn::{
|
||||||
punctuated::{Pair, Punctuated},
|
punctuated::{Pair, Punctuated},
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token::{Brace, Paren},
|
token::{Brace, Paren},
|
||||||
Attribute, Expr, ExprArray, ExprCall, ExprGroup, ExprPath, ExprRepeat, ExprStruct, ExprTuple,
|
Attribute, Expr, ExprArray, ExprCall, ExprGroup, ExprPath, ExprStruct, ExprTuple, FieldValue,
|
||||||
FieldValue, Ident, Index, Member, Path, PathArguments, PathSegment, Token, TypePath,
|
Ident, Index, Member, Path, PathArguments, PathSegment, Token, TypePath,
|
||||||
};
|
};
|
||||||
|
|
||||||
options! {
|
options! {
|
||||||
|
@ -351,18 +351,6 @@ impl Visitor {
|
||||||
}
|
}
|
||||||
parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_array)}
|
parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_array)}
|
||||||
}
|
}
|
||||||
pub(crate) fn process_hdl_repeat(
|
|
||||||
&mut self,
|
|
||||||
hdl_attr: HdlAttr<Nothing>,
|
|
||||||
mut expr_repeat: ExprRepeat,
|
|
||||||
) -> Expr {
|
|
||||||
self.require_normal_module(hdl_attr);
|
|
||||||
let repeated_value = &expr_repeat.expr;
|
|
||||||
*expr_repeat.expr = parse_quote_spanned! {repeated_value.span()=>
|
|
||||||
::fayalite::expr::ToExpr::to_expr(&(#repeated_value))
|
|
||||||
};
|
|
||||||
parse_quote! {::fayalite::expr::ToExpr::to_expr(&#expr_repeat)}
|
|
||||||
}
|
|
||||||
pub(crate) fn process_struct_enum(
|
pub(crate) fn process_struct_enum(
|
||||||
&mut self,
|
&mut self,
|
||||||
hdl_attr: HdlAttr<AggregateLiteralOptions>,
|
hdl_attr: HdlAttr<AggregateLiteralOptions>,
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
//! proc macros for `fayalite`
|
|
||||||
//!
|
|
||||||
//! see `fayalite::hdl_module` and `fayalite::ty::Value` for docs
|
|
||||||
|
|
||||||
// intentionally not documented here, see `fayalite::hdl_module` for docs
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn hdl_module(
|
pub fn hdl_module(
|
||||||
attr: proc_macro::TokenStream,
|
attr: proc_macro::TokenStream,
|
||||||
|
@ -16,7 +11,6 @@ pub fn hdl_module(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// intentionally not documented here, see `fayalite::ty::Value` for docs
|
|
||||||
#[proc_macro_derive(Value, attributes(hdl))]
|
#[proc_macro_derive(Value, attributes(hdl))]
|
||||||
pub fn value_derive(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn value_derive(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
match fayalite_proc_macros_impl::value_derive(item.into()) {
|
match fayalite_proc_macros_impl::value_derive(item.into()) {
|
||||||
|
|
|
@ -105,8 +105,8 @@ impl CanonicalValue for Clock {
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Value)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Value)]
|
||||||
#[hdl(fixed_type, outline_generated)]
|
#[hdl(fixed_type, outline_generated)]
|
||||||
pub struct ClockDomain {
|
pub struct ClockDomain {
|
||||||
pub clk: Clock,
|
pub clock: Clock,
|
||||||
pub rst: Reset,
|
pub reset: Reset,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToClock {
|
pub trait ToClock {
|
||||||
|
|
|
@ -2013,21 +2013,21 @@ impl<'a> Exporter<'a> {
|
||||||
self.targeted_annotations(module_name, vec![], &annotations);
|
self.targeted_annotations(module_name, vec![], &annotations);
|
||||||
let name = self.module.ns.get(reg.name_id());
|
let name = self.module.ns.get(reg.name_id());
|
||||||
let ty = self.type_state.ty(reg.ty());
|
let ty = self.type_state.ty(reg.ty());
|
||||||
let clk = self.expr(reg.clock_domain().clk.to_dyn(), &definitions, false);
|
let clock = self.expr(reg.clock_domain().clock.to_dyn(), &definitions, false);
|
||||||
if let Some(init) = reg.init() {
|
if let Some(init) = reg.init() {
|
||||||
let rst =
|
let reset =
|
||||||
self.expr(reg.clock_domain().rst.to_dyn(), &definitions, false);
|
self.expr(reg.clock_domain().reset.to_dyn(), &definitions, false);
|
||||||
let init = self.expr(init.to_dyn(), &definitions, false);
|
let init = self.expr(init.to_dyn(), &definitions, false);
|
||||||
writeln!(
|
writeln!(
|
||||||
body,
|
body,
|
||||||
"{indent}regreset {name}: {ty}, {clk}, {rst}, {init}{}",
|
"{indent}regreset {name}: {ty}, {clock}, {reset}, {init}{}",
|
||||||
FileInfo::new(reg.source_location()),
|
FileInfo::new(reg.source_location()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
writeln!(
|
writeln!(
|
||||||
body,
|
body,
|
||||||
"{indent}reg {name}: {ty}, {clk}{}",
|
"{indent}reg {name}: {ty}, {clock}{}",
|
||||||
FileInfo::new(reg.source_location()),
|
FileInfo::new(reg.source_location()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -1,273 +1,10 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
// TODO: enable:
|
|
||||||
// #![warn(missing_docs)]
|
|
||||||
|
|
||||||
#![doc = include_str!("../README.md")]
|
|
||||||
//!
|
|
||||||
//! # Organization
|
|
||||||
//!
|
|
||||||
//! All Fayalite-based designs are organized as one or more [modules][`module::Module`]
|
|
||||||
//! -- modules are created by writing a Rust function with the
|
|
||||||
//! [`#[hdl_module]` attribute][hdl_module]. You can then invoke the function to create a module.
|
|
||||||
//! You use the implicitly-added [`m: ModuleBuilder`][`module::ModuleBuilder`] variable in that
|
|
||||||
//! function to add inputs/outputs and other components to that module.
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! # use fayalite::{hdl_module, int::UInt};
|
|
||||||
//! #
|
|
||||||
//! #[hdl_module]
|
|
||||||
//! pub fn example_module() {
|
|
||||||
//! #[hdl]
|
|
||||||
//! let an_input: UInt<10> = m.input(); // create an input that is a 10-bit unsigned integer
|
|
||||||
//! #[hdl]
|
|
||||||
//! let some_output: UInt<10> = m.output();
|
|
||||||
//! m.connect(some_output, an_input); // assigns the value of `an_input` to `some_output`
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
extern crate self as fayalite;
|
extern crate self as fayalite;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use std as __std;
|
pub use std as __std;
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
#[doc(alias = "hdl")]
|
|
||||||
/// The `#[hdl_module]` attribute is applied to a Rust function so that that function creates
|
|
||||||
/// a [`Module`][`::fayalite::module::Module`] when called.
|
|
||||||
/// In the function body it will implicitly create a
|
|
||||||
/// variable [`m: ModuleBuilder`][`module::ModuleBuilder`].
|
|
||||||
///
|
|
||||||
/// # Module Kinds
|
|
||||||
///
|
|
||||||
/// There are two different kinds of modules:
|
|
||||||
///
|
|
||||||
/// * Normal modules. These are used for general Fayalite-based code.
|
|
||||||
/// These use the [`NormalModule`][`module::NormalModule`] tag type.
|
|
||||||
/// * Extern modules. These are for when you want to use modules written in
|
|
||||||
/// some other language, such as Verilog.
|
|
||||||
/// You create an extern module by instead using an `#[hdl_module(extern)]` attribute on your
|
|
||||||
/// module function. You then create inputs/outputs like for normal modules, then you can set
|
|
||||||
/// the verilog name and parameters using [`ModuleBuilder`][`module::ModuleBuilder`] methods:
|
|
||||||
///
|
|
||||||
/// * [`verilog_name()`][`module::ModuleBuilder::verilog_name`]
|
|
||||||
/// * [`parameter_int()`][`module::ModuleBuilder::parameter_int`]
|
|
||||||
/// * [`parameter_str()`][`module::ModuleBuilder::parameter_str`]
|
|
||||||
/// * [`parameter_raw_verilog()`][`module::ModuleBuilder::parameter_raw_verilog`]
|
|
||||||
/// * [`parameter()`][`module::ModuleBuilder::parameter`]
|
|
||||||
///
|
|
||||||
/// These use the [`ExternModule`][`module::ExternModule`] tag type.
|
|
||||||
///
|
|
||||||
/// # Module Function Bodies
|
|
||||||
///
|
|
||||||
/// The `#[hdl_module]` attribute lets you have statements/expressions with `#[hdl]` annotations
|
|
||||||
/// and `_hdl_` integer literals in the function body:
|
|
||||||
///
|
|
||||||
/// ## `_hdl_` integer literals
|
|
||||||
///
|
|
||||||
/// You can have integer literals with an arbitrary number of bits like so:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # #[fayalite::hdl_module]
|
|
||||||
/// # fn module() {
|
|
||||||
/// let a = 0x1234_hdl_u14; // a UInt<14> with value 0x1234
|
|
||||||
/// let b = 0x7_hdl_i3; // a SInt<3> with value 0x7
|
|
||||||
/// let lf = b'\n'_hdl; // a UInt<8> with value b'\n' -- aka. 0x0A
|
|
||||||
/// let large_a = b'A'_hdl; // a UInt<8> with value b'A' -- aka. 0x41
|
|
||||||
/// let n5 = -5_hdl_i4; // a SInt<4> with value -5
|
|
||||||
/// let n1 = -1_hdl_i200; // a SInt<200> with value -1
|
|
||||||
/// let v = 0xfedcba9876543210_fedcba9876543210_fedcba9876543210_hdl_u192; // a UInt<192>
|
|
||||||
/// let empty = 0_hdl_u0; // a UInt<0>
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## `#[hdl] let` statements
|
|
||||||
///
|
|
||||||
/// ### Inputs/Outputs
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use fayalite::{hdl_module, int::UInt, array::Array};
|
|
||||||
/// # #[hdl_module]
|
|
||||||
/// # fn module() {
|
|
||||||
/// #[hdl]
|
|
||||||
/// let my_input: UInt<10> = m.input();
|
|
||||||
/// #[hdl]
|
|
||||||
/// let my_output: Array<[UInt<10>; 3]> = m.output();
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Module Instances
|
|
||||||
///
|
|
||||||
/// module instances are kinda like the hardware equivalent of calling a function,
|
|
||||||
/// you can create them like so:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use fayalite::{hdl_module, int::UInt, array::Array};
|
|
||||||
/// # #[hdl_module]
|
|
||||||
/// # fn module() {
|
|
||||||
/// #[hdl]
|
|
||||||
/// let my_instance = m.instance(some_module());
|
|
||||||
/// // now you can use `my_instance`'s inputs/outputs like so:
|
|
||||||
/// #[hdl]
|
|
||||||
/// let v: UInt<3> = m.input();
|
|
||||||
/// m.connect(my_instance.a, v);
|
|
||||||
/// #[hdl_module]
|
|
||||||
/// fn some_module() {
|
|
||||||
/// #[hdl]
|
|
||||||
/// let a: UInt<3> = m.input();
|
|
||||||
/// // ...
|
|
||||||
/// }
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Registers
|
|
||||||
///
|
|
||||||
/// Registers are memory devices that will change their state only on a clock
|
|
||||||
/// edge (or when being reset). They retain their state when not connected to.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use fayalite::{hdl_module, int::UInt, array::Array, clock::ClockDomain};
|
|
||||||
/// # #[hdl_module]
|
|
||||||
/// # fn module() {
|
|
||||||
/// # let v = true;
|
|
||||||
/// #[hdl]
|
|
||||||
/// let cd: ClockDomain = m.input();
|
|
||||||
/// #[hdl]
|
|
||||||
/// let my_register: UInt<8> = m.reg_builder().clock_domain(cd).reset(8_hdl_u8);
|
|
||||||
/// #[hdl]
|
|
||||||
/// if v {
|
|
||||||
/// // my_register is only changed when both `v` is set and `cd`'s clock edge occurs.
|
|
||||||
/// m.connect(my_register, 0x45_hdl_u8);
|
|
||||||
/// }
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Wires
|
|
||||||
///
|
|
||||||
/// Wires are kinda like variables, but unlike registers,
|
|
||||||
/// they have no memory (they're combinatorial).
|
|
||||||
/// You must [connect][`module::ModuleBuilder::connect`] to all wires, so they have a defined value.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use fayalite::{hdl_module, int::UInt, array::Array, clock::ClockDomain};
|
|
||||||
/// # #[hdl_module]
|
|
||||||
/// # fn module() {
|
|
||||||
/// # let v = true;
|
|
||||||
/// #[hdl]
|
|
||||||
/// let cd: ClockDomain = m.input();
|
|
||||||
/// #[hdl]
|
|
||||||
/// let my_register: UInt<8> = m.reg_builder().clock_domain(cd).reset(8_hdl_u8);
|
|
||||||
/// #[hdl]
|
|
||||||
/// if v {
|
|
||||||
/// // my_register is only changed when both `v` is set and `cd`'s clock edge occurs.
|
|
||||||
/// m.connect(my_register, 0x45_hdl_u8);
|
|
||||||
/// }
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### Memories
|
|
||||||
///
|
|
||||||
/// Memories are optimized for storing large amounts of data.
|
|
||||||
///
|
|
||||||
/// When you create a memory, you get a [`MemBuilder`][`memory::MemBuilder`], which you
|
|
||||||
/// can then use to add memory ports, which is how you can read/write the memory.
|
|
||||||
///
|
|
||||||
/// There are several different ways to create a memory:
|
|
||||||
///
|
|
||||||
/// ### using [`ModuleBuilder::memory()`][`module::ModuleBuilder::memory`]
|
|
||||||
///
|
|
||||||
/// This way you have to set the [`depth`][`memory::MemBuilder::depth`] separately.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use fayalite::{hdl_module, int::UInt, clock::ClockDomain};
|
|
||||||
/// # #[hdl_module]
|
|
||||||
/// # fn module() {
|
|
||||||
/// // first, we need some IO
|
|
||||||
/// #[hdl]
|
|
||||||
/// let cd: ClockDomain = m.input();
|
|
||||||
/// #[hdl]
|
|
||||||
/// let read_addr: UInt<8> = m.input();
|
|
||||||
/// #[hdl]
|
|
||||||
/// let read_data: UInt<8> = m.output();
|
|
||||||
///
|
|
||||||
/// // now create the memory
|
|
||||||
/// #[hdl]
|
|
||||||
/// let mut my_memory = m.memory();
|
|
||||||
/// my_memory.depth(256); // the memory has 256 elements
|
|
||||||
///
|
|
||||||
/// let read_port = my_memory.new_read_port();
|
|
||||||
///
|
|
||||||
/// // connect up the read port
|
|
||||||
/// m.connect_any(read_port.addr, read_addr);
|
|
||||||
/// m.connect(read_port.en, 1_hdl_u1);
|
|
||||||
/// m.connect(read_port.clk, cd.clk);
|
|
||||||
/// m.connect(read_data, read_port.data);
|
|
||||||
///
|
|
||||||
/// // we need more IO for the write port
|
|
||||||
/// #[hdl]
|
|
||||||
/// let write_addr: UInt<8> = m.input();
|
|
||||||
/// #[hdl]
|
|
||||||
/// let do_write: UInt<1> = m.input();
|
|
||||||
/// #[hdl]
|
|
||||||
/// let write_data: UInt<8> = m.input();
|
|
||||||
///
|
|
||||||
/// let write_port = my_memory.new_write_port();
|
|
||||||
///
|
|
||||||
/// m.connect_any(write_port.addr, write_addr);
|
|
||||||
/// m.connect(write_port.en, do_write);
|
|
||||||
/// m.connect(write_port.clk, cd.clk);
|
|
||||||
/// m.connect(write_port.data, write_port.data);
|
|
||||||
/// m.connect(write_port.mask, 1_hdl_u1);
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### using [`ModuleBuilder::memory_array()`][`module::ModuleBuilder::memory_array`]
|
|
||||||
///
|
|
||||||
/// this allows you to specify the memory's underlying array type directly.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use fayalite::{hdl_module, int::UInt, memory::MemBuilder};
|
|
||||||
/// # #[hdl_module]
|
|
||||||
/// # fn module() {
|
|
||||||
/// #[hdl]
|
|
||||||
/// let mut my_memory: MemBuilder<[UInt<8>; 256]> = m.memory_array();
|
|
||||||
///
|
|
||||||
/// let read_port = my_memory.new_read_port();
|
|
||||||
/// // ...
|
|
||||||
/// let write_port = my_memory.new_write_port();
|
|
||||||
/// // ...
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ### using [`ModuleBuilder::memory_with_init()`][`module::ModuleBuilder::memory_with_init`]
|
|
||||||
///
|
|
||||||
/// This allows you to deduce the memory's array type from the data used to initialize the memory.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use fayalite::{hdl_module, int::UInt};
|
|
||||||
/// # #[hdl_module]
|
|
||||||
/// # fn module() {
|
|
||||||
/// # #[hdl]
|
|
||||||
/// # let read_addr: UInt<2> = m.input();
|
|
||||||
/// #[hdl]
|
|
||||||
/// let mut my_memory = m.memory_with_init(
|
|
||||||
/// #[hdl]
|
|
||||||
/// [0x12_hdl_u8, 0x34_hdl_u8, 0x56_hdl_u8, 0x78_hdl_u8],
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// let read_port = my_memory.new_read_port();
|
|
||||||
/// // note that `read_addr` is `UInt<2>` since the memory only has 4 elements
|
|
||||||
/// m.connect_any(read_port.addr, read_addr);
|
|
||||||
/// // ...
|
|
||||||
/// let write_port = my_memory.new_write_port();
|
|
||||||
/// // ...
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # `#[hdl]` expressions/statements:
|
|
||||||
///
|
|
||||||
/// FIXME: finish writing
|
|
||||||
pub use fayalite_proc_macros::hdl_module;
|
pub use fayalite_proc_macros::hdl_module;
|
||||||
|
|
||||||
pub mod annotations;
|
pub mod annotations;
|
||||||
|
|
|
@ -1108,8 +1108,6 @@ impl ModuleBody {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The runtime representation of a Fayalite module. The preferred way to create a [`Module`] is by
|
|
||||||
/// calling a function annotated with the [`#[hdl_module]`][`crate::hdl_module`] attribute.
|
|
||||||
#[derive(PartialEq, Eq, Hash)]
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
pub struct Module<T: BundleValue>
|
pub struct Module<T: BundleValue>
|
||||||
where
|
where
|
||||||
|
|
|
@ -28,7 +28,6 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use fayalite_proc_macros::Value;
|
pub use fayalite_proc_macros::Value;
|
||||||
|
|
||||||
mod sealed {
|
mod sealed {
|
||||||
|
|
|
@ -31,8 +31,8 @@ pub fn my_module(width: usize) {
|
||||||
let rst: SyncReset = m.input();
|
let rst: SyncReset = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let clock_domain: ClockDomain = m.wire();
|
let clock_domain: ClockDomain = m.wire();
|
||||||
m.connect(clock_domain.clk, clk);
|
m.connect(clock_domain.clock, clk);
|
||||||
m.connect(clock_domain.rst, rst.to_reset());
|
m.connect(clock_domain.reset, rst.to_reset());
|
||||||
#[hdl]
|
#[hdl]
|
||||||
let i: UInt<8> = m.input();
|
let i: UInt<8> = m.input();
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
@ -57,7 +57,7 @@ pub fn my_module(width: usize) {
|
||||||
m.connect(
|
m.connect(
|
||||||
o,
|
o,
|
||||||
#[hdl]
|
#[hdl]
|
||||||
[r, r, b'\r'_hdl],
|
[r, r, 13_hdl_u8],
|
||||||
);
|
);
|
||||||
m.connect(o[1], 30_hdl_u8);
|
m.connect(o[1], 30_hdl_u8);
|
||||||
m.connect(o2, i2);
|
m.connect(o2, i2);
|
||||||
|
@ -94,7 +94,7 @@ fn test_mymodule() {
|
||||||
circuit my_module:
|
circuit my_module:
|
||||||
type Ty0 = {`0`: UInt<32>, `1`: SInt<5>}
|
type Ty0 = {`0`: UInt<32>, `1`: SInt<5>}
|
||||||
type Ty1 = {|A, B: UInt<8>, C: UInt<1>[3]|}
|
type Ty1 = {|A, B: UInt<8>, C: UInt<1>[3]|}
|
||||||
type Ty2 = {clk: Clock, rst: Reset}
|
type Ty2 = {clock: Clock, `reset`: Reset}
|
||||||
type Ty3 = {flip i: UInt<8>, o: UInt<8>}
|
type Ty3 = {flip i: UInt<8>, o: UInt<8>}
|
||||||
module my_module: @[module-XXXXXXXXXX.rs 1:1]
|
module my_module: @[module-XXXXXXXXXX.rs 1:1]
|
||||||
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
|
input clk: Clock @[module-XXXXXXXXXX.rs 2:1]
|
||||||
|
@ -106,14 +106,14 @@ circuit my_module:
|
||||||
output o3: Ty0 @[module-XXXXXXXXXX.rs 11:1]
|
output o3: Ty0 @[module-XXXXXXXXXX.rs 11:1]
|
||||||
output o4: Ty1 @[module-XXXXXXXXXX.rs 20:1]
|
output o4: Ty1 @[module-XXXXXXXXXX.rs 20:1]
|
||||||
wire clock_domain: Ty2 @[module-XXXXXXXXXX.rs 4:1]
|
wire clock_domain: Ty2 @[module-XXXXXXXXXX.rs 4:1]
|
||||||
connect clock_domain.clk, clk @[module-XXXXXXXXXX.rs 5:1]
|
connect clock_domain.clock, clk @[module-XXXXXXXXXX.rs 5:1]
|
||||||
connect clock_domain.rst, rst @[module-XXXXXXXXXX.rs 6:1]
|
connect clock_domain.`reset`, rst @[module-XXXXXXXXXX.rs 6:1]
|
||||||
wire _bundle_literal_expr: Ty0
|
wire _bundle_literal_expr: Ty0
|
||||||
connect _bundle_literal_expr.`0`, UInt<32>(0h5)
|
connect _bundle_literal_expr.`0`, UInt<32>(0h5)
|
||||||
connect _bundle_literal_expr.`1`, SInt<5>(-0h3)
|
connect _bundle_literal_expr.`1`, SInt<5>(-0h3)
|
||||||
connect o3, _bundle_literal_expr @[module-XXXXXXXXXX.rs 12:1]
|
connect o3, _bundle_literal_expr @[module-XXXXXXXXXX.rs 12:1]
|
||||||
inst m2 of module2 @[module-XXXXXXXXXX.rs 13:1]
|
inst m2 of module2 @[module-XXXXXXXXXX.rs 13:1]
|
||||||
regreset r: UInt<8>, clock_domain.clk, clock_domain.rst, UInt<8>(0h8) @[module-XXXXXXXXXX.rs 14:1]
|
regreset r: UInt<8>, clock_domain.clock, clock_domain.`reset`, UInt<8>(0h8) @[module-XXXXXXXXXX.rs 14:1]
|
||||||
connect m2.i, i @[module-XXXXXXXXXX.rs 15:1]
|
connect m2.i, i @[module-XXXXXXXXXX.rs 15:1]
|
||||||
connect r, m2.o @[module-XXXXXXXXXX.rs 16:1]
|
connect r, m2.o @[module-XXXXXXXXXX.rs 16:1]
|
||||||
wire _array_literal_expr: UInt<8>[3]
|
wire _array_literal_expr: UInt<8>[3]
|
||||||
|
@ -138,41 +138,6 @@ circuit my_module:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[hdl_module(outline_generated)]
|
|
||||||
pub fn check_array_repeat() {
|
|
||||||
#[hdl]
|
|
||||||
let i: UInt<8> = m.input();
|
|
||||||
#[hdl]
|
|
||||||
let o: Array<[UInt<8>; 3]> = m.output();
|
|
||||||
m.connect(
|
|
||||||
o,
|
|
||||||
#[hdl]
|
|
||||||
[i; 3],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_array_repeat() {
|
|
||||||
let _n = SourceLocation::normalize_files_for_tests();
|
|
||||||
let m = check_array_repeat();
|
|
||||||
dbg!(m);
|
|
||||||
#[rustfmt::skip] // work around https://github.com/rust-lang/rustfmt/issues/6161
|
|
||||||
assert_export_firrtl! {
|
|
||||||
m =>
|
|
||||||
"/test/check_array_repeat.fir": r"FIRRTL version 3.2.0
|
|
||||||
circuit check_array_repeat:
|
|
||||||
module check_array_repeat: @[module-XXXXXXXXXX.rs 1:1]
|
|
||||||
input i: UInt<8> @[module-XXXXXXXXXX.rs 2:1]
|
|
||||||
output o: UInt<8>[3] @[module-XXXXXXXXXX.rs 3:1]
|
|
||||||
wire _array_literal_expr: UInt<8>[3]
|
|
||||||
connect _array_literal_expr[0], i
|
|
||||||
connect _array_literal_expr[1], i
|
|
||||||
connect _array_literal_expr[2], i
|
|
||||||
connect o, _array_literal_expr @[module-XXXXXXXXXX.rs 4:1]
|
|
||||||
",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[hdl_module(outline_generated)]
|
#[hdl_module(outline_generated)]
|
||||||
pub fn check_partially_written() {
|
pub fn check_partially_written() {
|
||||||
#[hdl]
|
#[hdl]
|
||||||
|
|
Loading…
Reference in a new issue