diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..03f4879 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-Ctarget-cpu=native"] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..14d9ccd --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,183 @@ +# This file is autogenerated by maturin v1.12.6 +# To update, run +# +# maturin generate-ci github +# +name: Release + +on: + push: + tags: ["v*"] + workflow_dispatch: + # TODO: Dry run when changing version in arbolta_pyo3/Cargo.toml + pull_request: + +permissions: + contents: read + +jobs: + linux: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: ubuntu-22.04 + target: x86_64 + - runner: ubuntu-22.04 + target: x86 + - runner: ubuntu-22.04 + target: aarch64 + - runner: ubuntu-22.04 + target: armv7 + - runner: ubuntu-22.04 + target: s390x + - runner: ubuntu-22.04 + target: ppc64le + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + with: + python-version: 3.x + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} + manylinux: auto + - name: Upload wheels + uses: actions/upload-artifact@v6 + with: + name: wheels-linux-${{ matrix.platform.target }} + path: dist + + musllinux: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: ubuntu-22.04 + target: x86_64 + - runner: ubuntu-22.04 + target: x86 + - runner: ubuntu-22.04 + target: aarch64 + - runner: ubuntu-22.04 + target: armv7 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + with: + python-version: 3.x + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} + manylinux: musllinux_1_2 + - name: Upload wheels + uses: actions/upload-artifact@v6 + with: + name: wheels-musllinux-${{ matrix.platform.target }} + path: dist + + windows: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: windows-latest + target: x64 + python_arch: x64 + - runner: windows-latest + target: x86 + python_arch: x86 + - runner: windows-11-arm + target: aarch64 + python_arch: arm64 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + with: + python-version: 3.13 + architecture: ${{ matrix.platform.python_arch }} + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} + - name: Upload wheels + uses: actions/upload-artifact@v6 + with: + name: wheels-windows-${{ matrix.platform.target }} + path: dist + + macos: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: macos-15-intel + target: x86_64 + - runner: macos-latest + target: aarch64 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + with: + python-version: 3.x + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.platform.target }} + args: --release --out dist --find-interpreter + sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} + - name: Upload wheels + uses: actions/upload-artifact@v6 + with: + name: wheels-macos-${{ matrix.platform.target }} + path: dist + + sdist: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Build sdist + uses: PyO3/maturin-action@v1 + with: + command: sdist + args: --out dist + - name: Upload sdist + uses: actions/upload-artifact@v6 + with: + name: wheels-sdist + path: dist + + release: + name: Release + runs-on: ubuntu-latest + if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }} + needs: [linux, musllinux, windows, macos, sdist] + permissions: + # Use to sign the release artifacts + id-token: write + # Used to upload release artifacts + contents: write + # Used to generate artifact attestation + attestations: write + steps: + - uses: actions/download-artifact@v7 + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v3 + with: + subject-path: 'wheels-*/*' + - name: Install uv + if: ${{ startsWith(github.ref, 'refs/tags/') }} + uses: astral-sh/setup-uv@v7 + - name: Publish to PyPI + if: ${{ startsWith(github.ref, 'refs/tags/') }} + run: uv publish 'wheels-*/*' + env: + UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.gitignore b/.gitignore index 015915c..b75d536 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ ### Python ### +uv.lock # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -157,4 +158,4 @@ Cargo.lock ### Generated ### examples/notebooks/*/output -synth_output +*.ruff_cache diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d942220..efa6577 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,3 @@ -exclude: '(examples/pre_synthesized_demo/i8bxi8bx16_vector_mac.json)' - repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 @@ -14,26 +12,30 @@ repos: - id: check-json - id: check-added-large-files - id: requirements-txt-fixer - - repo: https://github.com/doublify/pre-commit-rust - rev: v1.0 + - repo: local hooks: - - id: fmt - name: fmt (rust) - - id: clippy - name: clippy (rust) + - id: cargo-fmt + name: cargo fmt + entry: cargo fmt --all -- --check + language: system + types: [rust] + - id: cargo-clippy + name: cargo clippy + entry: cargo clippy --workspace --all-targets -- -Dclippy::all + pass_filenames: false + language: system + types: [rust] - id: cargo-check - name: cargo-check (rust) - - repo: https://github.com/pycqa/isort - rev: 5.13.2 + name: cargo check + entry: cargo check --workspace --all-targets + pass_filenames: false + language: system + types: [rust] + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.11.8 hooks: - - id: isort - name: isort (python) - - repo: https://github.com/google/yapf - rev: v0.43.0 - hooks: - - id: yapf - name: yapf (python) - args: ["-i"] + - id: ruff + - id: ruff-format - repo: https://github.com/srstevenson/nb-clean rev: 4.0.1 hooks: diff --git a/rustfmt.toml b/.rustfmt.toml similarity index 100% rename from rustfmt.toml rename to .rustfmt.toml diff --git a/Cargo.toml b/Cargo.toml index d767148..1e98b54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,32 @@ [workspace] members = ["crates/*"] -resolver = "2" +resolver = "3" + +[workspace.package] +edition = "2024" +repository = "https://github.com/KastnerRG/arbolta" +homepage = "https://github.com/KastnerRG/arbolta" +authors = ["Alexander Redding "] +license = "MIT" + +[workspace.dependencies] +anyhow = "1" +arbolta = { path = "crates/arbolta" } +derive_more = { version = "2", features = ["full"] } +enum_dispatch = "0.3" +indexmap = "2.12" +ndarray = "0.16.1" +num-traits = "0.2" +once_cell = "1.21" +petgraph = { version = "0.8.3", features = ["serde-1"] } +postcard = "1" +rstest = "0.26" +serde = { version = "1", features = ["derive"] } +thiserror = "2.0" +yosys-netlist-json = { git = "https://github.com/alexredd99/yosys-netlist-json.git" } + +[profile.release] +lto = true +codegen-units = 1 +opt-level = 3 +debug = false diff --git a/LICENSE b/LICENSE index c7649b4..ca978de 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License -Copyright (c) 2024 - 2025 Advanced Micro Devices, Inc. All rights reserved. +Copyright (c) 2024 - 2025 Advanced Micro Devices, Inc. +Copyright (c) 2026 Alexander Redding Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crates/arbolta/Cargo.toml b/crates/arbolta/Cargo.toml index 63beab4..586566a 100644 --- a/crates/arbolta/Cargo.toml +++ b/crates/arbolta/Cargo.toml @@ -1,15 +1,31 @@ [package] name = "arbolta" version = "0.1.0" -authors = ["AMD Research & Advanced Development"] -edition = "2021" +authors = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +description = "Core Arbolta hardware simulator" +exclude = [ + "tests/*" +] [dependencies] -serde = { version = "1.0", features = ["derive"] } -ndarray = "0.16.1" -num-traits = "0.2" -once_cell = "1.19.0" -rstest = "0.23.0" -flexbuffers = "2.0.0" -yosys-netlist-json = { git = "https://github.com/alexredd99/yosys-netlist-json.git" } -thiserror = "2.0.3" +anyhow = { workspace = true } +derive-new = "0.7" +derive_more = { workspace = true } +enum_dispatch = { workspace = true } +indexmap = { workspace = true } +inventory = "0.3.21" +ndarray = { workspace = true } +num-traits = { workspace = true } +once_cell = { workspace = true } +paste = "1.0.15" +petgraph = { workspace = true } +postcard = { workspace = true } +rstest = { workspace = true } +serde = { workspace = true } +serde_json = "1.0.145" +thiserror = { workspace = true } +yosys-netlist-json = { workspace = true } diff --git a/crates/arbolta/src/bit.rs b/crates/arbolta/src/bit.rs index 9439d51..4380130 100644 --- a/crates/arbolta/src/bit.rs +++ b/crates/arbolta/src/bit.rs @@ -1,135 +1,95 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding // SPDX-License-Identifier: MIT -use core::fmt; -use ndarray::{Array1, ArrayView1, ArrayViewMut1}; -use num_traits::PrimInt; +use anyhow::Result; +use derive_more::{BitAnd, BitOr, BitXor, Debug, IntoIterator, Not}; +use num_traits::{PrimInt, WrappingAdd, WrappingShl, WrappingSub}; use serde::{Deserialize, Serialize}; -use std::convert::{From, Into}; -use std::fmt::Debug; -use std::ops::{BitAnd, BitOr, BitXor, Not}; -use std::str::FromStr; +use std::{ + convert::{From, Into}, + fmt, + str::FromStr, +}; use thiserror::Error; /// Primitive signal value -#[derive(Debug, Clone, Eq, Copy, PartialEq, Deserialize, Serialize, Default)] -pub enum Bit { - #[default] - Zero, - One, -} +#[repr(transparent)] +#[derive( + Debug, + Clone, + Eq, + Copy, + PartialEq, + Deserialize, + derive_more::From, + derive_more::Into, + Serialize, + Default, + BitAnd, + BitOr, + BitXor, + Not, +)] +pub struct Bit(#[debug("{}", if *_0 {"1"} else {"0"})] pub bool); #[derive(Debug, PartialEq, Eq, Error)] -#[error("error converting bits")] -pub struct ParseBitError; - -impl From for Bit { - fn from(val: bool) -> Self { - if val { - Self::One - } else { - Self::Zero - } - } -} - -impl From for bool { - fn from(val: Bit) -> Self { - match val { - Bit::Zero => false, - Bit::One => true, - } - } +#[error("Couldn't convert `{0}` to a Bit, must be 0 or 1")] +pub enum ParseBitError { + Char(char), + Int(String), // Easier than using generics } -impl TryFrom for Bit { - type Error = ParseBitError; - fn try_from(val: char) -> Result { - match val { - '0' => Ok(Self::Zero), - '1' => Ok(Self::One), - _ => Err(ParseBitError), - } - } -} +impl Bit { + pub const ZERO: Bit = Bit(false); + pub const ONE: Bit = Bit(true); -impl From for char { - fn from(bit: Bit) -> Self { - match bit { - Bit::Zero => '0', - Bit::One => '1', + pub fn to_int(self) -> T { + match self { + Self(false) => T::zero(), + Self(true) => T::one(), } } -} -impl Bit { - pub fn from_int(val: T) -> Result { + pub fn from_int(val: T) -> Result { if val == T::zero() { - Ok(Self::Zero) + Ok(Self::ZERO) } else if val == T::one() { - Ok(Self::One) + Ok(Self::ONE) } else { - Err(ParseBitError) - } - } - - pub fn to_int(self) -> T { - match self { - Self::Zero => T::zero(), - Self::One => T::one(), + Err(ParseBitError::Int(format!("{val}"))) } } } -impl FromStr for Bit { - type Err = ParseBitError; - - fn from_str(s: &str) -> Result { - let int_val = s.parse::().or(Err(ParseBitError))?; - Self::from_int(int_val) - } -} - -impl Not for Bit { - type Output = Self; - - fn not(self) -> Self::Output { - match self { - Bit::Zero => Bit::One, - Bit::One => Bit::Zero, +impl TryFrom for Bit { + type Error = ParseBitError; + fn try_from(val: char) -> Result { + match val { + '0' => Ok(Bit::ZERO), + '1' => Ok(Bit::ONE), + _ => Err(ParseBitError::Char(val)), } } } -impl BitAnd for Bit { - type Output = Self; - - fn bitand(self, rhs: Self) -> Self::Output { - match &[self, rhs] { - [Bit::Zero, Bit::Zero] | [Bit::Zero, Bit::One] | [Bit::One, Bit::Zero] => Bit::Zero, - [Bit::One, Bit::One] => Bit::One, - } +impl From<&Bit> for Bit { + fn from(val: &Bit) -> Self { + *val } } -impl BitOr for Bit { - type Output = Self; - - fn bitor(self, rhs: Self) -> Self::Output { - match &[self, rhs] { - [Bit::Zero, Bit::Zero] => Bit::Zero, - [Bit::Zero, Bit::One] | [Bit::One, Bit::Zero] | [Bit::One, Bit::One] => Bit::One, - } +impl From<&bool> for Bit { + fn from(val: &bool) -> Self { + (*val).into() } } -impl BitXor for Bit { - type Output = Self; - - fn bitxor(self, rhs: Self) -> Self::Output { - match &[self, rhs] { - [Bit::Zero, Bit::Zero] | [Bit::One, Bit::One] => Bit::Zero, - [Bit::Zero, Bit::One] | [Bit::One, Bit::Zero] => Bit::One, +impl From for char { + fn from(bit: Bit) -> Self { + match bit { + Bit::ZERO => '0', + Bit::ONE => '1', } } } @@ -141,16 +101,30 @@ impl fmt::Display for Bit { } /// Structure for storing+manipulating a vector of `Bit`s -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Default, IntoIterator)] pub struct BitVec { + #[into_iterator(owned, ref, ref_mut)] pub bits: Vec, + pub shape: [usize; 2], +} + +impl From> for BitVec { + fn from(bits: Vec) -> Self { + let shape = [1, bits.len()]; + Self { bits, shape } + } +} + +impl From for Vec { + fn from(value: BitVec) -> Self { + value.bits.iter().map(|&b| b.into()).collect() + } } impl fmt::Display for BitVec { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let bit_string: String = self - .bits - .iter() + .into_iter() .rev() .map(|b| >::into(*b)) .collect(); @@ -166,44 +140,7 @@ impl FromStr for BitVec { for c in s.chars().rev() { bits.push(Bit::try_from(c)?); } - Ok(Self { bits }) - } -} - -impl From> for BitVec { - fn from(bits: Vec) -> Self { - Self { bits } - } -} - -impl From for Vec { - fn from(val: BitVec) -> Self { - val.bits - } -} - -impl From<&BitVec> for Vec { - fn from(val: &BitVec) -> Self { - val.bits.iter().rev().map(|b| (*b).into()).collect() - } -} - -impl From for Vec { - fn from(val: BitVec) -> Self { - val.bits.iter().rev().map(|b| (*b).into()).collect() - } -} - -impl From<&[bool]> for BitVec { - fn from(vals: &[bool]) -> Self { - let bits: Vec = vals.iter().rev().map(|b| (*b).into()).collect(); - Self::from(bits) - } -} - -impl From> for BitVec { - fn from(vals: Vec) -> Self { - Self::from(vals.as_slice()) + Ok(bits.into()) } } @@ -214,291 +151,122 @@ impl TryFrom<&str> for BitVec { for c in value.chars().rev() { bits.push(Bit::try_from(c)?); } - Ok(Self { bits }) + Ok(bits.into()) } } impl From for String { fn from(val: BitVec) -> Self { val - .bits - .iter() + .into_iter() .rev() - .map(|b| >::into(*b)) + .map(>::into) .collect() } } -impl Default for BitVec { - fn default() -> Self { - Self::new() + +impl FromIterator for BitVec { + fn from_iter>(iter: I) -> Self { + iter + .into_iter() + .map(|b| b.into()) + .collect::>() + .into() } } impl BitVec { - pub fn new() -> Self { - Self { bits: vec![] } + pub fn len(&self) -> usize { + self.bits.len() } - /// Convert int to vector of `Bit`s. - /// - /// # Arguments - /// * `val` - Int to convert. - /// * `size` - Number of bits to use. - fn int_to_bits_sized(val: T, size: usize) -> Result, ParseBitError> { - let mut bits: Vec = vec![]; - for n in 0..size { - bits.push(Bit::from_int((val >> n) & T::one())?); - } - - Ok(bits) - } - - /// Convert `Bit`s to int. - /// Automatically extends sign if target int type is signed. - fn bits_to_int(bits: &[Bit]) -> T { - let mut val: T; - let bit_ints: Vec = bits.iter().map(|b| b.to_int()).collect(); - - // Signed bits, need to sign extend - if *bit_ints.last().unwrap() == T::one() && T::min_value() != T::zero() { - val = !T::zero(); - bit_ints - .iter() - .enumerate() - .for_each(|(i, b)| val ^= (*b ^ T::one()) << i); - } else { - val = T::zero(); - bit_ints - .iter() - .enumerate() - .for_each(|(i, b)| val ^= *b << i); - } - - val - } - - /// Convert slice of `Bit`s to vector of ints. - /// - /// # Arguments - /// * `bits` - Slice of `Bit`s to convert. - /// * `elem_size` - Number of bits per int. - fn bits_to_ints(bits: &[Bit], elem_size: usize) -> Vec { - bits - .chunks(elem_size) - .map(|chunk| Self::bits_to_int(chunk)) - .collect() - } - - /// Convert slice of `Bit`s to vector of ints and store in buffer. - /// - /// # Arguments - /// * `bits` - Slice of `Bit`s to convert. - /// * `elem_size` - Number of bits per int. - /// * `buffer` - Buffer to store ints. - fn bits_to_ints_buffer( - bits: &[Bit], - elem_size: usize, - buffer: &mut [T], - ) { - bits - .chunks(elem_size) - .enumerate() - .for_each(|(i, chunk)| buffer[i] = Self::bits_to_int(chunk)); - } - // --- Integer Conversion Helpers --- - - /// Create from int. - /// - /// # Arguments - /// * `val` - Int to convert. - /// * `size` - Number of bits to use. - pub fn from_int_sized(val: T, size: usize) -> Result { - let bits = Self::int_to_bits_sized(val, size)?; - Ok(Self::from(bits)) + pub fn is_empty(&self) -> bool { + self.bits.is_empty() } /// Create from int. /// /// # Arguments /// * `val` - Int to convert. - pub fn from_int(val: T) -> Result { - let type_size = std::mem::size_of::() * 8; // bytes to bits - let bits = Self::int_to_bits_sized(val, type_size)?; - Ok(Self::from(bits)) - } - - /// Convert to int. - pub fn to_int(&self) -> T { - Self::bits_to_int(&self.bits) - } - - /// Create from slice of ints. - /// - /// # Arguments - /// * `vals` - Ints to convert. - /// * `elem_size` - Number of bits per int. - pub fn from_ints_sized(vals: &[T], elem_size: usize) -> Result { - let mut bits: Vec = vec![]; - for val in vals { - bits.append(&mut Self::int_to_bits_sized(*val, elem_size)?); + /// * `size` - Number of bits to use. Defaults to `sizeof(T)` * 8. + pub fn from_int(val: T, size: Option) -> Self { + let bit_width = std::mem::size_of::() * 8; + let size = size.unwrap_or(bit_width); + // Have to do this since no support for right shift without panic + let mut bits = (0..size.min(bit_width)) + .map(|n| Bit::from((val >> n) & T::one() == T::one())) + .collect::>(); + + // Have to pad + if bits.len() < size { + let is_signed = T::min_value() != T::zero(); + let sign_bit_set: bool = bits.last().is_some_and(|&b| b.into()); + let pad_bit: Bit = (is_signed && sign_bit_set).into(); + + let pad_size = size - bits.len(); + bits.extend(std::iter::repeat_n(pad_bit, pad_size)); } - Ok(Self::from(bits)) - } - - /// Create from slice of ints. - /// - /// # Arguments - /// * `vals` - Ints to convert. - pub fn from_ints(vals: &[T]) -> Result { - let type_size = std::mem::size_of::() * 8; // bytes to bits - Self::from_ints_sized(vals, type_size) - } - - /// Convert to vector of ints. - pub fn to_ints(&self) -> Vec { - let type_size = std::mem::size_of::() * 8; // bytes to bits - Self::bits_to_ints(&self.bits, type_size) - } - - /// Convert to ints and store in buffer. - /// - /// # Arguments - /// * `buffer` - Buffer to store ints. - pub fn to_ints_buffer(&self, buffer: &mut [T]) { - let type_size = std::mem::size_of::() * 8; // bytes to bits - Self::bits_to_ints_buffer(&self.bits, type_size, buffer); - } - - /// Convert to vector of ints. - /// - /// # Arguments - /// * `elem_size` - Number of bits per int. - pub fn to_ints_sized(&self, elem_size: usize) -> Vec { - Self::bits_to_ints(&self.bits, elem_size) - } - - /// Convert to ints and store in buffer. - /// - /// # Arguments - /// * `elem_size` - Number of bits per int. - /// * `buffer` - Buffer to store ints. - pub fn to_ints_sized_buffer( - &self, - elem_size: usize, - buffer: &mut [T], - ) { - Self::bits_to_ints_buffer(&self.bits, elem_size, buffer); + bits.into() } - /// Create from `ndarray` of ints. + /// Create from iterator of ints. /// /// # Arguments /// * `vals` - Ints to convert. - /// * `elem_size` - Number of bits per int. - pub fn from_int_ndarray_sized( - vals: ArrayView1, - elem_size: usize, - ) -> Result { - let mut bits: Vec = vec![]; - for val in vals { - bits.append(&mut Self::int_to_bits_sized(*val, elem_size)?); - } - Ok(Self::from(bits)) - } - - /// Create from `ndarray` of ints. - /// - /// # Arguments - /// * `vals` - Ints to convert. - pub fn from_int_ndarray(vals: ArrayView1) -> Result { - let type_size = std::mem::size_of::() * 8; // bytes to bits - Self::from_int_ndarray_sized(vals, type_size) - } - - /// Create from `ndarray` of bools. - /// - /// # Arguments - /// * `vals` - Bools to convert. - pub fn from_bool_ndarray(vals: ArrayView1) -> Result { - match vals.as_slice() { - None => Err(ParseBitError), - Some(buffer_slice) => Ok(Self::from(buffer_slice)), - } - } - - /// Convert to `ndarray` of ints. - /// - /// # Arguments - /// * `elem_size` - Number of bits per int. - pub fn to_int_ndarray_sized( - &self, - elem_size: usize, - ) -> Array1 { - Array1::from_vec(Self::bits_to_ints(&self.bits, elem_size)) - } - - /// Convert to ints and store in `ndarray`. - /// - /// # Arguments - /// * `elem_size` - Number of bits per int. - /// * `buffer` - `ndarray` buffer to store ints. - pub fn to_int_ndarray_sized_buffer( - &self, - elem_size: usize, - mut buffer: ArrayViewMut1, - ) -> Result<(), ParseBitError> { - match buffer.as_slice_mut() { - None => Err(ParseBitError), - Some(buffer_slice) => { - Self::bits_to_ints_buffer(&self.bits, elem_size, buffer_slice); - Ok(()) - } + /// * `elem_size` - Number of bits per int. Defaults to `sizeof(T)` * 8. + pub fn from_ints(vals: I, elem_size: Option) -> Self + where + T: PrimInt, + I: IntoIterator, + { + let elem_size = elem_size.unwrap_or(std::mem::size_of::() * 8); // bytes to bits + let bits = vals + .into_iter() + .flat_map(|v| Self::from_int(v, Some(elem_size))) + .collect::>(); + let size = bits.len() / elem_size; + Self { + bits, + shape: [size, elem_size], } } - /// Convert to ints and store in `ndarray`. - /// - /// # Arguments - /// * `buffer` - `ndarray` buffer to store ints. - pub fn to_int_ndarray_buffer( - &self, - mut buffer: ArrayViewMut1, - ) -> Result<(), ParseBitError> { - let type_size = std::mem::size_of::() * 8; // bytes to bits - match buffer.as_slice_mut() { - None => Err(ParseBitError), - Some(buffer_slice) => { - Self::bits_to_ints_buffer(&self.bits, type_size, buffer_slice); - Ok(()) - } + /// Convert to int. + /// Automatically extends sign if target int type is signed. + pub fn to_int(&self) -> T { + let mut val = T::zero(); + self + .bits + .iter() + .enumerate() + .for_each(|(i, bit)| val = val.wrapping_add(&(*bit).to_int::().wrapping_shl(i as u32))); + + // Signed int and negative value, need to sign extend + if T::min_value() != T::zero() && self.bits.last().is_some_and(|&b| b.into()) { + let mask = !T::one() + .wrapping_shl(self.bits.len() as u32 - 1) + .wrapping_sub(&T::one()); + val = val | mask; } - } - /// Convert to `ndarray` of ints. - pub fn to_int_ndarray(&self) -> Array1 { - let type_size = std::mem::size_of::() * 8; // bytes to bits - Array1::from_vec(Self::bits_to_ints(&self.bits, type_size)) + val } - /// Convert to bools and store in `ndarray`. + /// Convert to iterator of ints. + /// Automatically extends sign if target int type is signed. /// /// # Arguments - /// * `buffer` - `ndarray` buffer to store bools. - pub fn to_bool_ndarray_buffer( + /// * `elem_size` - Number of bits per int. Defaults to `sizeof(T)` * 8. + pub fn to_ints( &self, - mut buffer: ArrayViewMut1, - ) -> Result<(), ParseBitError> { - match buffer.as_slice_mut() { - None => Err(ParseBitError), - Some(buffer_slice) => { - self - .bits - .iter() - .enumerate() - .for_each(|(i, b)| buffer_slice[i] = (*b).into()); - Ok(()) - } - } + elem_size: Option, + ) -> impl Iterator + '_ { + // let elem_size = elem_size.unwrap_or(std::mem::size_of::() * 8); + let elem_size = elem_size.unwrap_or(self.shape[1]); + self + .bits + .chunks(elem_size) + .map(|chunk| Self::from(chunk.to_vec()).to_int()) } } diff --git a/crates/arbolta/src/cell.rs b/crates/arbolta/src/cell.rs deleted file mode 100644 index 59e0795..0000000 --- a/crates/arbolta/src/cell.rs +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use crate::bit::Bit; -use crate::signal::{AccessSignal, SignalIndex, SignalList}; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use thiserror::Error; - -pub const CONNECTION_SIZE: usize = 8; -pub const STATE_SIZE: usize = 2; - -/// Basic logic gate functions. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] -pub enum Function { - Inverter, - And, - Nor, - Nand, - Xor, - Xnor, - Or, - DffPosEdge, - Buf, -} - -/// Proxy for entry in a Liberty Cell Library. -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct CellInfo { - pub name: String, - pub function: Function, - pub area: f64, - pub num_inputs: usize, -} - -/// Proxy for a standard-cell and basic unit of 'compute'. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] -pub struct Cell { - /// Name of cell. - pub name: String, - /// Cell's function. - pub function: Function, - /// For storing cell state (ex, last clock value). - pub state: [Bit; STATE_SIZE], - /// Number of inputs the cell has. - pub num_inputs: usize, - /// Input signal indices. - pub input_connections: [SignalIndex; CONNECTION_SIZE], // Put this on stack - /// Output signal index. - pub output_connection: SignalIndex, -} - -#[derive(Debug, Error)] -pub enum CellError { - #[error("couldn't find cell `{0}`")] - NotFound(String), -} - -impl From<&CellInfo> for Cell { - fn from(value: &CellInfo) -> Self { - Self { - name: value.name.clone(), - function: value.function.clone(), - state: [Bit::Zero; STATE_SIZE], - num_inputs: value.num_inputs, - input_connections: [0; CONNECTION_SIZE], - output_connection: 0, - } - } -} - -impl From for Cell { - fn from(value: CellInfo) -> Self { - Cell::from(&value) - } -} - -/// Proxy for a Liberty Cell Library -/// User can define their own cells -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct CellLibrary { - pub cells: HashMap, -} - -impl CellLibrary { - /// Generate a cell given its name - /// # Arguments - /// * `cell_name` - Name of cell to generate - pub fn generate_cell(&self, cell_name: &str) -> Result { - match self.cells.get(cell_name) { - Some(cell_info) => Ok(Cell::from(cell_info)), - None => Err(CellError::NotFound(cell_name.to_string())), - } - } - - pub fn get_cell_area(&self, cell_name: &str) -> Result { - match self.cells.get(cell_name) { - Some(cell_info) => Ok(cell_info.area), - None => Err(CellError::NotFound(cell_name.to_string())), - } - } - - pub fn get_cell_breakdown_area( - &self, - breakdown: &HashMap, - ) -> Result { - let mut total_area: f64 = 0.0; - for (cell_name, count) in breakdown { - total_area += (*count as f64) * self.get_cell_area(cell_name)?; - } - - Ok(total_area) - } -} - -impl Cell { - pub fn empty_from_function(function: Function) -> Self { - Self { - name: String::new(), - function, - state: [Bit::Zero; STATE_SIZE], - num_inputs: 0, - input_connections: [0; CONNECTION_SIZE], - output_connection: 0, - } - } - - pub fn eval(&mut self, signals: &mut SignalList) { - let mut output_bit: Bit; - - match &self.function { - Function::Buf => { - output_bit = signals[self.input_connections[0]].get_value(); - } - Function::Inverter => { - output_bit = !signals[self.input_connections[0]].get_value(); - } - Function::And => { - output_bit = signals[self.input_connections[0]].get_value(); - for bit in self.input_connections[1..self.num_inputs] - .iter() - .map(|i| signals[*i].get_value()) - { - output_bit = output_bit & bit; - } - } - Function::Or => { - output_bit = signals[self.input_connections[0]].get_value(); - for bit in self.input_connections[1..self.num_inputs] - .iter() - .map(|i| signals[*i].get_value()) - { - output_bit = output_bit | bit; - } - } - Function::Nor => { - output_bit = signals[self.input_connections[0]].get_value(); - for bit in self.input_connections[1..self.num_inputs] - .iter() - .map(|i| signals[*i].get_value()) - { - output_bit = output_bit | bit; - } - output_bit = !output_bit; - } - Function::Nand => { - output_bit = signals[self.input_connections[0]].get_value(); - for bit in self.input_connections[1..self.num_inputs] - .iter() - .map(|i| signals[*i].get_value()) - { - output_bit = output_bit & bit; - } - output_bit = !output_bit; - } - Function::Xor => { - output_bit = signals[self.input_connections[0]].get_value(); - for bit in self.input_connections[1..self.num_inputs] - .iter() - .map(|i| signals[*i].get_value()) - { - output_bit = output_bit ^ bit; - } - } - Function::Xnor => { - output_bit = signals[self.input_connections[0]].get_value(); - for bit in self.input_connections[1..self.num_inputs] - .iter() - .map(|i| signals[*i].get_value()) - { - output_bit = output_bit ^ bit; - } - output_bit = !output_bit; - } - Function::DffPosEdge => { - let (clock, data) = ( - signals[self.input_connections[0]].get_value(), - signals[self.input_connections[1]].get_value(), - ); - let (last_data, last_clock) = (self.state[0], self.state[1]); - // Detect rising edge, clock new data - output_bit = if clock == Bit::One && last_clock == Bit::Zero { - data - } else { - last_data - }; - self.state = [output_bit, clock]; - } - }; - signals[self.output_connection].set_value(output_bit); - } - - pub fn reset(&mut self) { - if self.function == Function::DffPosEdge { - self.state = [Bit::Zero; 2] - } - } -} - -pub fn default_cell_library() -> CellLibrary { - let cells = HashMap::from([ - ( - "BUF".to_string(), - CellInfo { - name: "BUF".to_string(), - function: Function::Buf, - area: 4.0, - num_inputs: 1, - }, - ), - ( - "NOT".to_string(), - CellInfo { - name: "NOT".to_string(), - function: Function::Inverter, - area: 2.0, - num_inputs: 1, - }, - ), - ( - "NAND".to_string(), - CellInfo { - name: "NAND".to_string(), - function: Function::Nand, - area: 4.0, - num_inputs: 2, - }, - ), - ( - "NOR".to_string(), - CellInfo { - name: "NOR".to_string(), - function: Function::Nor, - area: 4.0, - num_inputs: 2, - }, - ), - ( - "DFF".to_string(), - CellInfo { - name: "DFF".to_string(), - function: Function::DffPosEdge, - area: 8.0, - num_inputs: 2, - }, - ), - ]); - - CellLibrary { cells } -} diff --git a/crates/arbolta/src/cell/mod.rs b/crates/arbolta/src/cell/mod.rs new file mode 100644 index 0000000..9706c9a --- /dev/null +++ b/crates/arbolta/src/cell/mod.rs @@ -0,0 +1,233 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +mod simcells; +mod simlib; +mod test_helpers; + +// Re-export +use crate::signal::Signals; +use enum_dispatch::enum_dispatch; +use once_cell::sync::Lazy; +use serde::{Deserialize, Serialize}; +pub use simcells::*; +pub use simlib::*; +use std::{ + collections::{BTreeMap, HashMap}, + env, +}; +use thiserror::Error; + +#[enum_dispatch] +pub trait CellFn { + fn eval(&mut self, signals: &mut Signals); + fn reset(&mut self); +} + +// connections, parameters +pub type CellCtor = fn(&BTreeMap<&str, Box<[usize]>>, &BTreeMap<&str, usize>) -> Cell; +pub type CellDispatchMap = HashMap<&'static str, CellCtor>; + +#[derive(derive_more::Constructor)] +pub struct CellRegistration { + pub aliases: &'static [&'static str], + pub ctor: CellCtor, +} + +inventory::collect!(CellRegistration); + +pub static CELL_DISPATCH: Lazy> = Lazy::new(|| { + let mut cell_map = HashMap::new(); + for registration in inventory::iter:: { + for name in registration.aliases { + cell_map.insert(*name, registration.ctor); + } + } + cell_map +}); + +#[enum_dispatch(CellFn)] +#[derive(Debug, Serialize, Deserialize, Clone)] +/// Proxy for a standard-cell and basic unit of 'compute'. +pub enum Cell { + // ASAP7 + Asap7Buf, + Asap7Inv, + Asap7And2, + Asap7And3, + Asap7And4, + Asap7And5, + Asap7FullAdderInv, + Asap7HalfAdderInv, + Asap7MajorityInv, + Asap7Majority, + Asap7Nand2, + Asap7Nand3, + Asap7Nand4, + Asap7Nand5, + Asap7Nor2, + Asap7Nor3, + Asap7Nor4, + Asap7Nor5, + Asap7Or2, + Asap7Or3, + Asap7Or4, + Asap7Or5, + Asap7TieHigh, + Asap7TieLow, + Asap7Xnor2, + Asap7Xor2, + Asap7Or2And1Or1Inv, + Asap7OrAnd211, + Asap7OrAnd21, + Asap7OrAnd221, + Asap7OrAnd222, + Asap7OrAnd22, + Asap7OrAnd31, + Asap7OrAnd331, + Asap7OrAnd332, + Asap7OrAnd333, + Asap7OrAnd33, + Asap7OrAndInv211, + Asap7OrAndInv21, + Asap7OrAndInv221, + Asap7OrAndInv222, + Asap7OrAndInv22, + Asap7OrAndInv311, + Asap7OrAndInv31, + Asap7OrAndInv321, + Asap7OrAndInv322, + Asap7OrAndInv32, + Asap7OrAndInv331, + Asap7OrAndInv332, + Asap7OrAndInv333, + Asap7OrAndInv33, + Asap7And2Or1And1Inv, + Asap7And2Or1And1Or1Inv, + Asap7AndOr211, + Asap7AndOr21, + Asap7AndOr221, + Asap7AndOr222, + Asap7AndOr22, + Asap7AndOr31, + Asap7AndOr322, + Asap7AndOr32, + Asap7AndOr331, + Asap7AndOr332, + Asap7AndOr333, + Asap7AndOr33, + Asap7AndOrInv211, + Asap7AndOrInv21, + Asap7AndOrInv221, + Asap7AndOrInv222, + Asap7AndOrInv22, + Asap7AndOrInv311, + Asap7AndOrInv31, + Asap7AndOrInv321, + Asap7AndOrInv322, + Asap7AndOrInv32, + Asap7AndOrInv331, + Asap7AndOrInv332, + Asap7AndOrInv333, + Asap7AndOrInv33, + Asap7DffInv, + // Sim Cells + // - Unary + Buffer, + Inverter, + // - Binary + And2, + AndNot2, + Nand2, + Nor2, + Or2, + OrNot2, + Xnor2, + Xor2, + // - Ternary + AndOrInvert3, + Mux2, + NMux2, + OrAndInvert3, + // - Memory + Dff, + DffReset, + // Sim Lib + // - Arithmetic + Add, + Div, + Equal, + GreaterEqual, + GreaterThan, + LessEqual, + LessThan, + Modulus, + Mul, + Negate, + NotEqual, + Sub, + // + DffAsyncLoad, + DffAsyncResetEnable, + BMux, + LogicAnd, + LogicNot, + LogicOr, + Mux, + Not, + PMux, + Pos, + ProcAnd, + ProcOr, + ProcXor, + ReduceAnd, + ReduceOr, + Reg, + Shl, + Shr, +} + +#[derive(Debug, Error)] +pub enum CellError { + #[error("Unsupported cell `{0}`")] + Unsupported(String), + #[error("Cell `{0}` not found in netlist")] + NotFound(String), + #[error("Direction `{0}` not supported")] + Direction(String), +} + +pub type CellMapping = HashMap>)>; + +pub fn create_cell( + cell_type: &str, + connections: &BTreeMap<&str, Box<[usize]>>, + parameters: &BTreeMap<&str, usize>, + mapping: Option<&CellMapping>, +) -> Result { + if env::var("ARBOLTA_DEBUG").is_ok() { + println!("Parsing cell `{cell_type}`") + } + + let (cell_type, connections) = if let Some(mapping) = mapping + && let Some((mapped_cell_type, mapped_connections)) = mapping.get(cell_type) + { + let connections = match mapped_connections { + Some(mapped_connections) => connections + .iter() + .map(|(&port_name, nets)| (mapped_connections[port_name].as_str(), nets.clone())) + .collect(), + None => connections.clone(), + }; + + (mapped_cell_type.as_str(), connections) + } else { + (cell_type, connections.clone()) + }; + + let ctor = CELL_DISPATCH + .get(cell_type) + .ok_or_else(|| CellError::Unsupported(cell_type.to_string()))?; + + Ok(ctor(&connections, parameters)) +} diff --git a/crates/arbolta/src/cell/simcells.rs b/crates/arbolta/src/cell/simcells.rs new file mode 100644 index 0000000..0dcd8ce --- /dev/null +++ b/crates/arbolta/src/cell/simcells.rs @@ -0,0 +1,1260 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use super::CellFn; +use crate::{bit::Bit, cell::CellRegistration, signal::Signals}; +use derive_more::Constructor; +use paste::paste; +use serde::{Deserialize, Serialize}; +use std::{collections::BTreeMap, env}; + +macro_rules! create_cell { + // 1-output, no inputs + ($rtl_names:expr, $cell_type:ident, $out_net:ident, $body:expr) => { + #[derive(Debug, Clone, Constructor, Serialize, Deserialize)] + pub struct $cell_type { + $out_net: usize + } + + impl CellFn for $cell_type { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + signals.set_net(self.$out_net, $body()); + } + + fn reset(&mut self) {} + } + + paste! { + inventory::submit! {CellRegistration::new($rtl_names, + |connections: &BTreeMap<&str, Box<[usize]>>, _parameters: &BTreeMap<&str, usize>| { + if env::var("ARBOLTA_DEBUG").is_ok() { + println!("Parsing connections: {:#?}", connections); + } + + $cell_type::new( + connections[stringify!([<$out_net:upper>])][0] + ).into() + })} + } + }; + + // 1-output, N-inputs + ($rtl_names:expr, $cell_type:ident { $($in_netn:ident),* $(,)?}, $out_net:ident, $body:expr) => { + #[allow(clippy::too_many_arguments)] + #[derive(Debug, Clone, Constructor, Serialize, Deserialize)] + pub struct $cell_type { + $( + $in_netn: usize, + )* + + $out_net: usize + } + + impl CellFn for $cell_type { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + $( + let $in_netn: Bit = signals.get_net(self.$in_netn); + )* + signals.set_net(self.$out_net, $body($($in_netn,)*)); + } + + fn reset(&mut self) {} + } + + paste! { + inventory::submit! {CellRegistration::new($rtl_names, + |connections: &BTreeMap<&str, Box<[usize]>>, _parameters: &BTreeMap<&str, usize>| { + if env::var("ARBOLTA_DEBUG").is_ok() { + println!("Parsing connections: {:#?}", connections); + } + + // Special case for buffers + let output_net = match connections.get(stringify!([<$out_net:upper>])) { + Some(nets) => nets[0], + None => 0 // Write to zero does nothing + }; + + $cell_type::new( + $( + connections[stringify!([<$in_netn:upper>])][0], + )* + output_net + ).into() + })} + } + }; + + // N-output, N-inputs + ($rtl_names:expr, $cell_type:ident { $($in_netn:ident),* $(,)?}, { $($out_netn:ident),+ $(,)?}, $body:expr) => { + #[derive(Debug, Clone, Constructor, Serialize, Deserialize)] + pub struct $cell_type { + $( + $in_netn: usize, + )* + + $( + $out_netn: usize, + )* + } + + impl CellFn for $cell_type { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + $( + let $in_netn: Bit = signals.get_net(self.$in_netn); + )* + + let ( $($out_netn),+ ) = $body($($in_netn,)*); + + $( + signals.set_net(self.$out_netn, $out_netn); + )+ + } + + fn reset(&mut self) {} + } + + paste! { + inventory::submit! {CellRegistration::new($rtl_names, + |connections: &BTreeMap<&str, Box<[usize]>>, _parameters: &BTreeMap<&str, usize>| { + if env::var("ARBOLTA_DEBUG").is_ok() { + println!("Parsing connections: {:#?}", connections); + } + + $cell_type::new( + $( + connections[stringify!([<$in_netn:upper>])][0], + )* + $( + connections[stringify!([<$out_netn:upper>])][0], + )* + ).into() + })} + } + }; +} + +/* ++++++++ Sim Cells ++++++++ */ +// Unary +create_cell!(&["$_BUF_"], Buffer { a }, y, |a: Bit| a); +create_cell!(&["$_NOT_"], Inverter { a }, y, |a: Bit| !a); + +// Binary +create_cell!(&["$_AND_"], And2 { a, b }, y, |a: Bit, b: Bit| a & b); +create_cell!(&["$_ANDNOT_"], AndNot2 { a, b }, y, |a: Bit, b: Bit| a & !b); +create_cell!(&["$_NAND_"], Nand2 { a, b }, y, |a: Bit, b: Bit| !(a & b)); +create_cell!(&["$_NOR_"], Nor2 { a, b }, y, |a: Bit, b: Bit| !(a | b)); +create_cell!(&["$_OR_"], Or2 { a, b }, y, |a: Bit, b: Bit| a | b); +create_cell!(&["$_ORNOT_"], OrNot2 { a, b }, y, |a: Bit, b: Bit| a | !b); +create_cell!(&["$_XNOR_"], Xnor2 { a, b }, y, |a: Bit, b: Bit| !(a ^ b)); +create_cell!(&["$_XOR_"], Xor2 { a, b }, y, |a: Bit, b: Bit| a ^ b); + +// Ternary +create_cell!( + &["$_AOI3_"], + AndOrInvert3 { a, b, c }, + y, + |a: Bit, b: Bit, c: Bit| { !((a & b) | c) } +); +create_cell!( + &["$_MUX_"], + Mux2 { a, b, s }, + y, + |a: Bit, b: Bit, select: Bit| if select.into() { b } else { a } +); +create_cell!( + &["$_NMUX_"], + NMux2 { a, b, s }, + y, + |a: Bit, b: Bit, select: Bit| if select.into() { !b } else { !a } +); +create_cell!( + &["$_OAI3_"], + OrAndInvert3 { a, b, c }, + y, + |a: Bit, b: Bit, c: Bit| { !((a | b) & c) } +); + +// Memory +#[derive(Debug, Clone, Serialize, Deserialize, derive_new::new)] +pub struct Dff { + polarity: Bit, + clock_net: usize, + data_in_net: usize, + data_out_net: usize, + #[new(default)] + last_clock: Bit, +} + +impl CellFn for Dff { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + // Check if clock active for any polarity + let clock = !(signals.get_net(self.clock_net) ^ self.polarity); + + // Rising edge + if clock == Bit::ONE && self.last_clock == Bit::ZERO { + let data_in = signals.get_net(self.data_in_net); + signals.set_net(self.data_out_net, data_in); + } + + self.last_clock = clock; + } + + fn reset(&mut self) { + self.last_clock = Bit::ZERO; + } +} + +inventory::submit! { + CellRegistration::new(&["$_DFF_P_"], + |connections: &BTreeMap<&str, Box<[usize]>>, _parameters: &BTreeMap<&str, usize>| { + Dff::new( + Bit::ONE, + connections["CLK"][0], + connections["D"][0], + connections["Q"][0], + ).into() + }) +} + +#[derive(Debug, Clone, Serialize, Deserialize, derive_new::new)] +pub struct DffReset { + clock_polarity: Bit, + reset_polarity: Bit, + reset_val: Bit, + clock_net: usize, + reset_net: usize, + data_in_net: usize, + data_out_net: usize, + #[new(default)] + last_clock: Bit, +} + +impl CellFn for DffReset { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + // Check if clock active for any polarity + let clock = !(signals.get_net(self.clock_net) ^ self.clock_polarity); + + // Rising edge + if clock == Bit::ONE && self.last_clock == Bit::ZERO { + // Check if reset active for any polarity + if signals.get_net(self.reset_net) == self.reset_polarity { + signals.set_net(self.data_out_net, self.reset_val); + } else { + let data_in = signals.get_net(self.data_in_net); + signals.set_net(self.data_out_net, data_in); + } + } + + self.last_clock = clock; + } + + fn reset(&mut self) { + self.last_clock = Bit::ZERO; + } +} + +inventory::submit! { + CellRegistration::new(&["$_SDFF_PP0_"], + |connections: &BTreeMap<&str, Box<[usize]>>, _parameters: &BTreeMap<&str, usize>| { + DffReset::new( + Bit::ONE, + Bit::ONE, + Bit::ZERO, + connections["C"][0], + connections["R"][0], + connections["D"][0], + connections["Q"][0], + ).into() + }) +} + +/* ++++++++ ASAP7 Cells ++++++++ */ +create_cell!( + &[ + "BUFx10_ASAP7_75t_R", + "BUFx12_ASAP7_75t_R", + "BUFx12f_ASAP7_75t_R", + "BUFx16f_ASAP7_75t_R", + "BUFx24_ASAP7_75t_R", + "BUFx2_ASAP7_75t_R", + "BUFx3_ASAP7_75t_R", + "BUFx4_ASAP7_75t_R", + "BUFx4f_ASAP7_75t_R", + "BUFx5_ASAP7_75t_R", + "BUFx6f_ASAP7_75t_R", + "BUFx8_ASAP7_75t_R", + "HB1xp67_ASAP7_75t_R", + "HB2xp67_ASAP7_75t_R", + "HB3xp67_ASAP7_75t_R", + "HB4xp67_ASAP7_75t_R", + ], + Asap7Buf { a }, + y, + |a: Bit| a +); +create_cell!( + &[ + "CKINVDCx10_ASAP7_75t_R", + "CKINVDCx11_ASAP7_75t_R", + "CKINVDCx12_ASAP7_75t_R", + "CKINVDCx14_ASAP7_75t_R", + "CKINVDCx16_ASAP7_75t_R", + "CKINVDCx20_ASAP7_75t_R", + "CKINVDCx5p33_ASAP7_75t_R", + "CKINVDCx6p67_ASAP7_75t_R", + "CKINVDCx8_ASAP7_75t_R", + "CKINVDCx9p33_ASAP7_75t_R", + "INVx11_ASAP7_75t_R", + "INVx13_ASAP7_75t_R", + "INVx1_ASAP7_75t_R", + "INVx2_ASAP7_75t_R", + "INVx3_ASAP7_75t_R", + "INVx4_ASAP7_75t_R", + "INVx5_ASAP7_75t_R", + "INVx6_ASAP7_75t_R", + "INVx8_ASAP7_75t_R", + "INVxp33_ASAP7_75t_R", + "INVxp67_ASAP7_75t_R", + ], + Asap7Inv { a }, + y, + |a: Bit| !a +); +create_cell!( + &[ + "AND2x2_ASAP7_75t_R", + "AND2x4_ASAP7_75t_R", + "AND2x6_ASAP7_75t_R", + ], + Asap7And2 { a, b }, + y, + |a: Bit, b: Bit| a & b +); +create_cell!( + &[ + "AND3x1_ASAP7_75t_R", + "AND3x2_ASAP7_75t_R", + "AND3x4_ASAP7_75t_R", + ], + Asap7And3 { a, b, c }, + y, + |a: Bit, b: Bit, c: Bit| a & b & c +); +create_cell!( + &["AND4x1_ASAP7_75t_R", "AND4x2_ASAP7_75t_R",], + Asap7And4 { a, b, c, d }, + y, + |a: Bit, b: Bit, c: Bit, d: Bit| a & b & c & d +); +create_cell!( + &["AND5x1_ASAP7_75t_R", "AND5x2_ASAP7_75t_R",], + Asap7And5 { a, b, c, d, e }, + y, + |a: Bit, b: Bit, c: Bit, d: Bit, e: Bit| a & b & c & d & e +); +create_cell!( + &["FAx1_ASAP7_75t_R"], + Asap7FullAdderInv {a, b, ci}, {sn, con}, + |a: Bit, b: Bit, carry_in: Bit| { + let sum = a ^ b; + (!(sum ^ carry_in), !((a & b) | (sum & carry_in))) + } +); +create_cell!( + &["HAxp5_ASAP7_75t_R"], + Asap7HalfAdderInv { a, b }, {sn, con}, |a: Bit, b: Bit| ( + !(a ^ b), + !(a & b) +)); +create_cell!( + &["MAJIxp5_ASAP7_75t_R"], + Asap7MajorityInv { a, b, c }, + y, + |a: Bit, b: Bit, c: Bit| (!a & !b) | (!a & !c) | (!b & !c) +); +create_cell!( + &["MAJx2_ASAP7_75t_R", "MAJx3_ASAP7_75t_R"], + Asap7Majority { a, b, c }, + y, + |a: Bit, b: Bit, c: Bit| (a & b) | (a & c) | (b & c) +); +create_cell!( + &[ + "NAND2x1_ASAP7_75t_R", + "NAND2x1p5_ASAP7_75t_R", + "NAND2x2_ASAP7_75t_R", + "NAND2xp33_ASAP7_75t_R", + "NAND2xp5_ASAP7_75t_R", + "NAND2xp67_ASAP7_75t_R", + ], + Asap7Nand2 { a, b }, + y, + |a: Bit, b: Bit| !(a & b) +); +create_cell!( + &[ + "NAND3x1_ASAP7_75t_R", + "NAND3x2_ASAP7_75t_R", + "NAND3xp33_ASAP7_75t_R", + ], + Asap7Nand3 { a, b, c }, + y, + |a: Bit, b: Bit, c: Bit| !(a & b & c) +); +create_cell!( + &["NAND4xp25_ASAP7_75t_R", "NAND4xp75_ASAP7_75t_R",], + Asap7Nand4 { a, b, c, d }, + y, + |a: Bit, b: Bit, c: Bit, d: Bit| !(a & b & c & d) +); +create_cell!( + &["NAND5xp2_ASAP7_75t_R",], + Asap7Nand5 { a, b, c, d, e }, + y, + |a: Bit, b: Bit, c: Bit, d: Bit, e: Bit| !(a & b & c & d & e) +); +create_cell!( + &[ + "NOR2x1_ASAP7_75t_R", + "NOR2x1p5_ASAP7_75t_R", + "NOR2x2_ASAP7_75t_R", + "NOR2xp33_ASAP7_75t_R", + "NOR2xp67_ASAP7_75t_R", + ], + Asap7Nor2 { a, b }, + y, + |a: Bit, b: Bit| !(a | b) +); +create_cell!( + &[ + "NOR3x1_ASAP7_75t_R", + "NOR3x2_ASAP7_75t_R", + "NOR3xp33_ASAP7_75t_R", + ], + Asap7Nor3 { a, b, c }, + y, + |a: Bit, b: Bit, c: Bit| !(a | b | c) +); +create_cell!( + &["NOR4xp25_ASAP7_75t_R", "NOR4xp75_ASAP7_75t_R"], + Asap7Nor4 { a, b, c, d }, + y, + |a: Bit, b: Bit, c: Bit, d: Bit| !(a | b | c | d) +); +create_cell!( + &["NOR5xp2_ASAP7_75t_R"], + Asap7Nor5 { a, b, c, d, e }, + y, + |a: Bit, b: Bit, c: Bit, d: Bit, e: Bit| !(a | b | c | d | e) +); +create_cell!( + &[ + "OR2x2_ASAP7_75t_R", + "OR2x4_ASAP7_75t_R", + "OR2x6_ASAP7_75t_R", + ], + Asap7Or2 { a, b }, + y, + |a: Bit, b: Bit| a | b +); +create_cell!( + &[ + "OR3x1_ASAP7_75t_R", + "OR3x2_ASAP7_75t_R", + "OR3x4_ASAP7_75t_R", + ], + Asap7Or3 { a, b, c }, + y, + |a: Bit, b: Bit, c: Bit| a | b | c +); +create_cell!( + &["OR4x1_ASAP7_75t_R", "OR4x2_ASAP7_75t_R"], + Asap7Or4 { a, b, c, d }, + y, + |a: Bit, b: Bit, c: Bit, d: Bit| a | b | c | d +); +create_cell!( + &["OR5x1_ASAP7_75t_R", "OR5x2_ASAP7_75t_R"], + Asap7Or5 { a, b, c, d, e }, + y, + |a: Bit, b: Bit, c: Bit, d: Bit, e: Bit| a | b | c | d | e +); +create_cell!(&["TIEHIx1_ASAP7_75t_R"], Asap7TieHigh, h, || Bit::ONE); +create_cell!(&["TIELOx1_ASAP7_75t_R"], Asap7TieLow, l, || Bit::ZERO); +create_cell!( + &[ + "XNOR2x1_ASAP7_75t_R", + "XNOR2x2_ASAP7_75t_R", + "XNOR2xp5_ASAP7_75t_R", + ], + Asap7Xnor2 { a, b }, + y, + |a: Bit, b: Bit| !(a ^ b) +); +create_cell!( + &[ + "XOR2x1_ASAP7_75t_R", + "XOR2x2_ASAP7_75t_R", + "XOR2xp5_ASAP7_75t_R", + ], + Asap7Xor2 { a, b }, + y, + |a: Bit, b: Bit| a ^ b +); +create_cell!( + &["O2A1O1Ixp33_ASAP7_75t_R", "O2A1O1Ixp5_ASAP7_75t_R"], + Asap7Or2And1Or1Inv { a1, a2, b, c }, + y, + |a1: Bit, a2: Bit, b: Bit, c: Bit| (!a1 & !a2 & !c) | (!b & !c) +); +create_cell!( + &["OA211x2_ASAP7_75t_R"], + Asap7OrAnd211 { a1, a2, b, c }, + y, + |a1: Bit, a2: Bit, b: Bit, c: Bit| (a1 & b & c) | (a2 & b & c) +); +create_cell!( + &["OA21x2_ASAP7_75t_R"], + Asap7OrAnd21 { a1, a2, b }, + y, + |a1: Bit, a2: Bit, b: Bit| (a1 & b) | (a2 & b) +); +create_cell!( + &["OA221x2_ASAP7_75t_R"], + Asap7OrAnd221 { a1, a2, b1, b2, c }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit, c: Bit| (a2 & b2 & c) + | (a2 & b1 & c) + | (a1 & b2 & c) + | (a1 & b1 & c) +); +create_cell!( + &["OA222x2_ASAP7_75t_R"], + Asap7OrAnd222 { + a1, + a2, + b1, + b2, + c1, + c2 + }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit, c1: Bit, c2: Bit| (a2 & b2 & c2) + | (a2 & b2 & c1) + | (a2 & b1 & c2) + | (a2 & b1 & c1) + | (a1 & b2 & c2) + | (a1 & b2 & c1) + | (a1 & b1 & c2) + | (a1 & b1 & c1) +); +create_cell!( + &["OA22x2_ASAP7_75t_R"], + Asap7OrAnd22 { a1, a2, b1, b2 }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit| (a2 & b2) | (a2 & b1) | (a1 & b2) | (a1 & b1) +); +create_cell!( + &["OA31x2_ASAP7_75t_R"], + Asap7OrAnd31 { a1, a2, a3, b1 }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit| (a3 & b1) | (a2 & b1) | (a1 & b1) +); +create_cell!( + &["OA331x1_ASAP7_75t_R", "OA331x2_ASAP7_75t_R"], + Asap7OrAnd331 { + a1, + a2, + a3, + b1, + b2, + b3, + c1, + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit, c1: Bit| (a3 & b3 & c1) + | (a3 & b2 & c1) + | (a3 & b1 & c1) + | (a2 & b3 & c1) + | (a2 & b2 & c1) + | (a2 & b1 & c1) + | (a1 & b3 & c1) + | (a1 & b2 & c1) + | (a1 & b1 & c1) +); +create_cell!( + &["OA332x1_ASAP7_75t_R", "OA332x2_ASAP7_75t_R",], + Asap7OrAnd332 { + a1, + a2, + a3, + b1, + b2, + b3, + c1, + c2, + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit, c1: Bit, c2: Bit| (a3 & b3 & c2) + | (a3 & b3 & c1) + | (a3 & b2 & c2) + | (a3 & b2 & c1) + | (a3 & b1 & c2) + | (a3 & b1 & c1) + | (a2 & b3 & c2) + | (a2 & b3 & c1) + | (a2 & b2 & c2) + | (a2 & b2 & c1) + | (a2 & b1 & c2) + | (a2 & b1 & c1) + | (a1 & b3 & c2) + | (a1 & b3 & c1) + | (a1 & b2 & c2) + | (a1 & b2 & c1) + | (a1 & b1 & c2) + | (a1 & b1 & c1) +); +create_cell!( + &["OA333x1_ASAP7_75t_R", "OA333x2_ASAP7_75t_R",], + Asap7OrAnd333 { + a1, + a2, + a3, + b1, + b2, + b3, + c1, + c2, + c3, + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit, c1: Bit, c2: Bit, c3: Bit| (a3 & b3 & c3) + | (a3 & b3 & c2) + | (a3 & b3 & c1) + | (a3 & b2 & c3) + | (a3 & b2 & c2) + | (a3 & b2 & c1) + | (a3 & b1 & c3) + | (a3 & b1 & c2) + | (a3 & b1 & c1) + | (a2 & b3 & c3) + | (a2 & b3 & c2) + | (a2 & b3 & c1) + | (a2 & b2 & c3) + | (a2 & b2 & c2) + | (a2 & b2 & c1) + | (a2 & b1 & c3) + | (a2 & b1 & c2) + | (a2 & b1 & c1) + | (a1 & b3 & c3) + | (a1 & b3 & c2) + | (a1 & b3 & c1) + | (a1 & b2 & c3) + | (a1 & b2 & c2) + | (a1 & b2 & c1) + | (a1 & b1 & c3) + | (a1 & b1 & c2) + | (a1 & b1 & c1) +); +create_cell!( + &["OA33x2_ASAP7_75t_R"], + Asap7OrAnd33 { + a1, + a2, + a3, + b1, + b2, + b3 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit| (a3 & b3) + | (a3 & b2) + | (a3 & b1) + | (a2 & b3) + | (a2 & b2) + | (a2 & b1) + | (a1 & b3) + | (a1 & b2) + | (a1 & b1) +); +create_cell!( + &["OAI211xp5_ASAP7_75t_R"], + Asap7OrAndInv211 { a1, a2, b, c }, + y, + |a1: Bit, a2: Bit, b: Bit, c: Bit| (!a1 & !a2) | !b | !c +); +create_cell!( + &[ + "OAI21x1_ASAP7_75t_R", + "OAI21xp33_ASAP7_75t_R", + "OAI21xp5_ASAP7_75t_R", + ], + Asap7OrAndInv21 { a1, a2, b }, + y, + |a1: Bit, a2: Bit, b: Bit| (!a1 & !a2) | !b +); +create_cell!( + &["OAI221xp5_ASAP7_75t_R"], + Asap7OrAndInv221 { a1, a2, b1, b2, c }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit, c: Bit| { (!a1 & !a2) | (!b1 & !b2) | !c } +); +create_cell!( + &["OAI222xp33_ASAP7_75t_R"], + Asap7OrAndInv222 { + a1, + a2, + b1, + b2, + c1, + c2 + }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit, c1: Bit, c2: Bit| (!a1 & !a2) | (!b1 & !b2) | (!c1 & !c2) +); +create_cell!( + &[ + "OAI22x1_ASAP7_75t_R", + "OAI22xp33_ASAP7_75t_R", + "OAI22xp5_ASAP7_75t_R" + ], + Asap7OrAndInv22 { a1, a2, b1, b2 }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit| (!a1 & !a2) | (!b1 & !b2) +); +create_cell!( + &["OAI311xp33_ASAP7_75t_R"], + Asap7OrAndInv311 { a1, a2, a3, b1, c1 }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, c1: Bit| (!a1 & !a2 & !a3) | !b1 | !c1 +); +create_cell!( + &["OAI31xp33_ASAP7_75t_R", "OAI31xp67_ASAP7_75t_R"], + Asap7OrAndInv31 { a1, a2, a3, b }, + y, + |a1: Bit, a2: Bit, a3: Bit, b: Bit| (!a1 & !a2 & !a3) | !b +); +create_cell!( + &["OAI321xp33_ASAP7_75t_R"], + Asap7OrAndInv321 { + a1, + a2, + a3, + b1, + b2, + c + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, c: Bit| (!a1 & !a2 & !a3) | (!b1 & !b2) | !c +); +create_cell!( + &["OAI322xp33_ASAP7_75t_R"], + Asap7OrAndInv322 { + a1, + a2, + a3, + b1, + b2, + c1, + c2 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, c1: Bit, c2: Bit| (!a1 & !a2 & !a3) + | (!b1 & !b2) + | (!c1 & !c2) +); +create_cell!( + &["OAI32xp33_ASAP7_75t_R"], + Asap7OrAndInv32 { a1, a2, a3, b1, b2 }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit| (!a1 & !a2 & !a3) | (!b1 & !b2) +); +create_cell!( + &["OAI331xp33_ASAP7_75t_R"], + Asap7OrAndInv331 { + a1, + a2, + a3, + b1, + b2, + b3, + c1 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit, c1: Bit| (!a1 & !a2 & !a3) + | (!b1 & !b2 & !b3) + | !c1 +); +create_cell!( + &["OAI332xp33_ASAP7_75t_R"], + Asap7OrAndInv332 { + a1, + a2, + a3, + b1, + b2, + b3, + c1, + c2 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit, c1: Bit, c2: Bit| (!a1 & !a2 & !a3) + | (!b1 & !b2 & !b3) + | (!c1 & !c2) +); +create_cell!( + &["OAI333xp33_ASAP7_75t_R"], + Asap7OrAndInv333 { + a1, + a2, + a3, + b1, + b2, + b3, + c1, + c2, + c3 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit, c1: Bit, c2: Bit, c3: Bit| (!a1 + & !a2 + & !a3) + | (!b1 & !b2 & !b3) + | (!c1 & !c2 & !c3) +); +create_cell!( + &["OAI33xp33_ASAP7_75t_R"], + Asap7OrAndInv33 { + a1, + a2, + a3, + b1, + b2, + b3 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit| (!a1 & !a2 & !a3) | (!b1 & !b2 & !b3) +); +create_cell!( + &["A2O1A1Ixp33_ASAP7_75t_R"], + Asap7And2Or1And1Inv { a1, a2, b, c }, + y, + |a1: Bit, a2: Bit, b: Bit, c: Bit| (!a1 & !b) | (!a2 & !b) | !c +); +create_cell!( + &["A2O1A1O1Ixp25_ASAP7_75t_R"], + Asap7And2Or1And1Or1Inv { a1, a2, b, c, d }, + y, + |a1: Bit, a2: Bit, b: Bit, c: Bit, d: Bit| (!a1 & !b & !d) | (!a2 & !b & !d) | (!c & !d) +); +create_cell!( + &["AO211x2_ASAP7_75t_R"], + Asap7AndOr211 { a1, a2, b, c }, + y, + |a1: Bit, a2: Bit, b: Bit, c: Bit| (a1 & a2) | b | c +); +create_cell!( + &["AO21x1_ASAP7_75t_R", "AO21x2_ASAP7_75t_R",], + Asap7AndOr21 { a1, a2, b }, + y, + |a1: Bit, a2: Bit, b: Bit| (a1 & a2) | b +); +create_cell!( + &["AO221x1_ASAP7_75t_R", "AO221x2_ASAP7_75t_R",], + Asap7AndOr221 { a1, a2, b1, b2, c }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit, c: Bit| (a1 & a2) | (b1 & b2) | c +); +create_cell!( + &["AO222x2_ASAP7_75t_R",], + Asap7AndOr222 { + a1, + a2, + b1, + b2, + c1, + c2 + }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit, c1: Bit, c2: Bit| (a1 & a2) | (b1 & b2) | (c1 & c2) +); +create_cell!( + &["AO22x1_ASAP7_75t_R", "AO22x2_ASAP7_75t_R",], + Asap7AndOr22 { a1, a2, b1, b2 }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit| (a1 & a2) | (b1 & b2) +); + +create_cell!( + &["AO31x2_ASAP7_75t_R"], + Asap7AndOr31 { a1, a2, a3, b }, + y, + |a1, a2, a3, b| (a1 & a2 & a3) | b +); +create_cell!( + &["AO322x2_ASAP7_75t_R"], + Asap7AndOr322 { + a1, + a2, + a3, + b1, + b2, + c1, + c2 + }, + y, + |a1, a2, a3, b1, b2, c1, c2| (a1 & a2 & a3) | (b1 & b2) | (c1 & c2) +); +create_cell!( + &["AO32x1_ASAP7_75t_R", "AO32x2_ASAP7_75t_R"], + Asap7AndOr32 { a1, a2, a3, b1, b2 }, + y, + |a1, a2, a3, b1, b2| (a1 & a2 & a3) | (b1 & b2) +); +create_cell!( + &["AO331x1_ASAP7_75t_R", "AO331x2_ASAP7_75t_R"], + Asap7AndOr331 { + a1, + a2, + a3, + b1, + b2, + b3, + c + }, + y, + |a1, a2, a3, b1, b2, b3, c| (a1 & a2 & a3) | (b1 & b2 & b3) | c +); +create_cell!( + &["AO332x1_ASAP7_75t_R", "AO332x2_ASAP7_75t_R"], + Asap7AndOr332 { + a1, + a2, + a3, + b1, + b2, + b3, + c1, + c2 + }, + y, + |a1, a2, a3, b1, b2, b3, c1, c2| (a1 & a2 & a3) | (b1 & b2 & b3) | (c1 & c2) +); +create_cell!( + &["AO333x1_ASAP7_75t_R", "AO333x2_ASAP7_75t_R"], + Asap7AndOr333 { + a1, + a2, + a3, + b1, + b2, + b3, + c1, + c2, + c3 + }, + y, + |a1, a2, a3, b1, b2, b3, c1, c2, c3| (a1 & a2 & a3) | (b1 & b2 & b3) | (c1 & c2 & c3) +); +create_cell!( + &["AO33x2_ASAP7_75t_R"], + Asap7AndOr33 { + a1, + a2, + a3, + b1, + b2, + b3 + }, + y, + |a1, a2, a3, b1, b2, b3| (a1 & a2 & a3) | (b1 & b2 & b3) +); +create_cell!( + &["AOI211x1_ASAP7_75t_R", "AOI211xp5_ASAP7_75t_R"], + Asap7AndOrInv211 { a1, a2, b, c }, + y, + |a1: Bit, a2: Bit, b: Bit, c: Bit| (!a1 & !b & !c) | (!a2 & !b & !c) +); +create_cell!( + &[ + "AOI21x1_ASAP7_75t_R", + "AOI21xp33_ASAP7_75t_R", + "AOI21xp5_ASAP7_75t_R" + ], + Asap7AndOrInv21 { a1, a2, b }, + y, + |a1: Bit, a2: Bit, b: Bit| (!a1 & !b) | (!a2 & !b) +); +create_cell!( + &["AOI221x1_ASAP7_75t_R", "AOI221xp5_ASAP7_75t_R"], + Asap7AndOrInv221 { a1, a2, b1, b2, c }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit, c: Bit| (!a1 & !b1 & !c) + | (!a1 & !b2 & !c) + | (!a2 & !b1 & !c) + | (!a2 & !b2 & !c) +); +create_cell!( + &["AOI222xp33_ASAP7_75t_R"], + Asap7AndOrInv222 { + a1, + a2, + b1, + b2, + c1, + c2 + }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit, c1: Bit, c2: Bit| (!a1 & !b1 & !c1) + | (!a1 & !b1 & !c2) + | (!a1 & !b2 & !c1) + | (!a1 & !b2 & !c2) + | (!a2 & !b1 & !c1) + | (!a2 & !b1 & !c2) + | (!a2 & !b2 & !c1) + | (!a2 & !b2 & !c2) +); +create_cell!( + &[ + "AOI22x1_ASAP7_75t_R", + "AOI22xp33_ASAP7_75t_R", + "AOI22xp5_ASAP7_75t_R" + ], + Asap7AndOrInv22 { a1, a2, b1, b2 }, + y, + |a1: Bit, a2: Bit, b1: Bit, b2: Bit| (!a1 & !b1) | (!a1 & !b2) | (!a2 & !b1) | (!a2 & !b2) +); +create_cell!( + &["AOI311xp33_ASAP7_75t_R"], + Asap7AndOrInv311 { a1, a2, a3, b, c }, + y, + |a1: Bit, a2: Bit, a3: Bit, b: Bit, c: Bit| (!a1 & !b & !c) | (!a2 & !b & !c) | (!a3 & !b & !c) +); +create_cell!( + &["AOI31xp33_ASAP7_75t_R", "AOI31xp67_ASAP7_75t_R"], + Asap7AndOrInv31 { a1, a2, a3, b }, + y, + |a1: Bit, a2: Bit, a3: Bit, b: Bit| (!a1 & !b) | (!a2 & !b) | (!a3 & !b) +); +create_cell!( + &["AOI321xp33_ASAP7_75t_R"], + Asap7AndOrInv321 { + a1, + a2, + a3, + b1, + b2, + c + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, c: Bit| (a1 & b1 & c) + | (a1 & b2 & c) + | (a2 & b1 & c) + | (a2 & b2 & c) + | (a3 & b1 & c) + | (a3 & b2 & c) +); +create_cell!( + &["AOI322xp5_ASAP7_75t_R"], + Asap7AndOrInv322 { + a1, + a2, + a3, + b1, + b2, + c1, + c2 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, c1: Bit, c2: Bit| (!a1 & !b1 & !c1) + | (!a1 & !b1 & !c2) + | (!a1 & !b2 & !c1) + | (!a1 & !b2 & !c2) + | (!a2 & !b1 & !c1) + | (!a2 & !b1 & !c2) + | (!a2 & !b2 & !c1) + | (!a2 & !b2 & !c2) + | (!a3 & !b1 & !c1) + | (!a3 & !b1 & !c2) + | (!a3 & !b2 & !c1) + | (!a3 & !b2 & !c2) +); +create_cell!( + &["AOI32xp33_ASAP7_75t_R"], + Asap7AndOrInv32 { a1, a2, a3, b1, b2 }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit| (!a1 & !b1) + | (!a1 & !b2) + | (!a2 & !b1) + | (!a2 & !b2) + | (!a3 & !b1) + | (!a3 & !b2) +); +create_cell!( + &["AOI331xp33_ASAP7_75t_R"], + Asap7AndOrInv331 { + a1, + a2, + a3, + b1, + b2, + b3, + c1 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit, c1: Bit| (!a1 & !b1 & !c1) + | (!a1 & !b2 & !c1) + | (!a1 & !b3 & !c1) + | (!a2 & !b1 & !c1) + | (!a2 & !b2 & !c1) + | (!a2 & !b3 & !c1) + | (!a3 & !b1 & !c1) + | (!a3 & !b2 & !c1) + | (!a3 & !b3 & !c1) +); +create_cell!( + &["AOI332xp33_ASAP7_75t_R"], + Asap7AndOrInv332 { + a1, + a2, + a3, + b1, + b2, + b3, + c1, + c2 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit, c1: Bit, c2: Bit| (!a1 & !b1 & !c1) + | (!a1 & !b1 & !c2) + | (!a1 & !b2 & !c1) + | (!a1 & !b2 & !c2) + | (!a1 & !b3 & !c1) + | (!a1 & !b3 & !c2) + | (!a2 & !b1 & !c1) + | (!a2 & !b1 & !c2) + | (!a2 & !b2 & !c1) + | (!a2 & !b2 & !c2) + | (!a2 & !b3 & !c1) + | (!a2 & !b3 & !c2) + | (!a3 & !b1 & !c1) + | (!a3 & !b1 & !c2) + | (!a3 & !b2 & !c1) + | (!a3 & !b2 & !c2) + | (!a3 & !b3 & !c1) + | (!a3 & !b3 & !c2) +); +create_cell!( + &["AOI333xp33_ASAP7_75t_R"], + Asap7AndOrInv333 { + a1, + a2, + a3, + b1, + b2, + b3, + c1, + c2, + c3 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit, c1: Bit, c2: Bit, c3: Bit| (!a1 + & !b1 + & !c1) + | (!a1 & !b1 & !c2) + | (!a1 & !b1 & !c3) + | (!a1 & !b2 & !c1) + | (!a1 & !b2 & !c2) + | (!a1 & !b2 & !c3) + | (!a1 & !b3 & !c1) + | (!a1 & !b3 & !c2) + | (!a1 & !b3 & !c3) + | (!a2 & !b1 & !c1) + | (!a2 & !b1 & !c2) + | (!a2 & !b1 & !c3) + | (!a2 & !b2 & !c1) + | (!a2 & !b2 & !c2) + | (!a2 & !b2 & !c3) + | (!a2 & !b3 & !c1) + | (!a2 & !b3 & !c2) + | (!a2 & !b3 & !c3) + | (!a3 & !b1 & !c1) + | (!a3 & !b1 & !c2) + | (!a3 & !b1 & !c3) + | (!a3 & !b2 & !c1) + | (!a3 & !b2 & !c2) + | (!a3 & !b2 & !c3) + | (!a3 & !b3 & !c1) + | (!a3 & !b3 & !c2) + | (!a3 & !b3 & !c3) +); +create_cell!( + &["AOI33xp33_ASAP7_75t_R"], + Asap7AndOrInv33 { + a1, + a2, + a3, + b1, + b2, + b3 + }, + y, + |a1: Bit, a2: Bit, a3: Bit, b1: Bit, b2: Bit, b3: Bit| (!a1 & !b1) + | (!a1 & !b2) + | (!a1 & !b3) + | (!a2 & !b1) + | (!a2 & !b2) + | (!a2 & !b3) + | (!a3 & !b1) + | (!a3 & !b2) + | (!a3 & !b3) +); + +#[derive(Debug, Clone, Serialize, Deserialize, derive_new::new)] +pub struct Asap7DffInv { + clock_net: usize, + data_in_net: usize, + data_out_net: usize, + #[new(default)] + last_clock: Bit, +} + +impl CellFn for Asap7DffInv { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + // Check if clock active for any polarity + let clock = signals.get_net(self.clock_net); + + // Rising edge + if clock == Bit::ONE && self.last_clock == Bit::ZERO { + let data_in = signals.get_net(self.data_in_net); + signals.set_net(self.data_out_net, !data_in); // Inverse + } + + self.last_clock = clock; + } + + fn reset(&mut self) { + self.last_clock = Bit::ZERO; + } +} + +inventory::submit! { + CellRegistration::new(&[ + "DFFHQNx1_ASAP7_75t_R", + "DFFHQNx2_ASAP7_75t_R", + "DFFHQNx3_ASAP7_75t_R", + ], + |connections: &BTreeMap<&str, Box<[usize]>>, _parameters: &BTreeMap<&str, usize>| { + Asap7DffInv::new( + connections["CLK"][0], + connections["D"][0], + connections["QN"][0], + ).into() + }) +} diff --git a/crates/arbolta/src/cell/simlib/arithmetic.rs b/crates/arbolta/src/cell/simlib/arithmetic.rs new file mode 100644 index 0000000..8093632 --- /dev/null +++ b/crates/arbolta/src/cell/simlib/arithmetic.rs @@ -0,0 +1,158 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use super::*; +use crate::{bit::BitVec, signal::Signals}; +use derive_more::Constructor; +use serde::{Deserialize, Serialize}; +use std::ops::Rem; + +define_arithmetic_cell!(&["$add"], Add { a, b }, y, a.wrapping_add(b)); +define_arithmetic_cell!(&["$div"], Div { a, b }, y, a.wrapping_div(b)); +define_arithmetic_cell!(&["$eq"], Equal { a, b }, y, a.eq(&b)); +define_arithmetic_cell!(&["$ge"], GreaterEqual { a, b }, y, a.ge(&b)); +define_arithmetic_cell!(&["$gt"], GreaterThan { a, b }, y, a.gt(&b)); +define_arithmetic_cell!(&["$le"], LessEqual { a, b }, y, a.le(&b)); +define_arithmetic_cell!(&["$lt"], LessThan { a, b }, y, a.lt(&b)); +define_arithmetic_cell!(&["$mod"], Modulus { a, b }, y, a.rem(b)); +define_arithmetic_cell!(&["$mul"], Mul { a, b }, y, a.wrapping_mul(b)); +define_arithmetic_cell!(&["$neg"], Negate { a }, y, a.wrapping_neg()); +define_arithmetic_cell!(&["$ne"], NotEqual { a, b }, y, a.ne(&b)); +define_arithmetic_cell!(&["$sub"], Sub { a, b }, y, a.wrapping_sub(b)); + +#[cfg(test)] +mod tests { + use super::*; + use crate::cell::test_helpers::*; + use rstest::rstest; + + #[rstest] + // 37738 + 4365 = 42103 + #[case::unsigned_normal(false, "1001001101101010", "0001000100001101", "1010010001110111")] + // 155 + 7 = 162 + #[case::unsigned_normal(false, "10011011", "111", "0000000010100010")] + // 54 + 4234 = 4288 + #[case::unsigned_normal(false, "00110110", "0001000010001010", "1000011000000")] + // 37738 + 4365 = 1143 + #[case::unsigned_overflow(false, "1001001101101010", "0001000100001101", "0010001110111")] + #[case(false, "00000111", "00000111", "00001110")] // 7 + 7 = 49 + #[case(false, "00000111", "111", "01110")] // 7 + 7 = 49 + #[case(false, "111", "111", "1110")] // 7 + 7 = 14 + #[case(false, "111", "111", "10")] // 7 + 7 = 4 (overflow) + #[case(true, "00000111", "00000111", "00001110")] // 7 + 7 = 49 + #[case(true, "00000111", "1001", "00000")] // 7 + -7 = 0 + #[case(true, "1001", "11001", "11110010")] // -7 + -7 = -14 + #[case(true, "1001", "1001", "10")] // -7 + -7 = -4 (overflow) + #[case(true, "111", "111", "10")] // 7 + 7 = 4 (overflow) + #[case(true, "1", "0", "111111111111")] // sign extend + #[case(true, "0", "1", "111111111111")] // sign extend + #[case(true, "1", "1", "111111111110")] // -1 + -1 = -2 + #[case(true, "01", "1", "000000000000")] // 1 + -1 = 0 + fn add(#[case] signed: bool, #[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + run_binary_cell_case_signed!(Add, signed, a, b, expected); + } + + #[rstest] + fn div() { + println!("TODO") + } + + #[rstest] + fn equal() { + println!("TODO") + } + + #[rstest] + #[case::zero_unsigned(false, "0000", "0000", "0001")] // 0 >= 0 + #[case::zero_signed(true, "0000", "0000", "0001")] // 0 >= 0 + #[case(false, "0000", "1111", "0000")] // 0 >= 15 + #[case(true, "0000", "1111", "0001")] // 0 >= -1 + #[case(false, "0111", "000011", "0001")] // 7 >= 3 + #[case(true, "0111", "000011", "0001")] // 7 >= 3 + fn greater_equal( + #[case] signed: bool, + #[case] a: BitVec, + #[case] b: BitVec, + #[case] expected: BitVec, + ) { + run_binary_cell_case_signed!(GreaterEqual, signed, a, b, expected); + } + + #[rstest] + fn greater_than() { + println!("TODO") + } + + #[rstest] + #[case::zero_unsigned(false, "0000", "0000", "1")] + #[case::zero_signed(true, "0000", "0000", "1")] + // 37738 < 4365 = 0 + #[case::unsigned_normal(false, "1001001101101010", "0001000100001101", "0")] + #[case::signed_normal(true, "1001001101101010", "0001000100001101", "1")] + #[case::unsigned_equal(false, "101010", "00101010", "1")] + fn less_equal( + #[case] signed: bool, + #[case] a: BitVec, + #[case] b: BitVec, + #[case] expected: BitVec, + ) { + run_binary_cell_case_signed!(LessEqual, signed, a, b, expected); + } + + #[rstest] + // 37738 < 4365 = 0 + #[case::unsigned_normal(false, "1001001101101010", "0001000100001101", "0")] + #[case::signed_normal(true, "1001001101101010", "0001000100001101", "1")] + #[case::unsigned_equal(false, "101010", "00101010", "0")] + fn less_than( + #[case] signed: bool, + #[case] a: BitVec, + #[case] b: BitVec, + #[case] expected: BitVec, + ) { + run_binary_cell_case_signed!(LessThan, signed, a, b, expected); + } + + #[rstest] + fn modulus() { + println!("TODO") + } + + #[rstest] + // 8712 * 5366 = 46748592 + #[case::unsigned_normal( + false, + "0010001000001000", + "0001010011110110", + "00000010110010010101001110110000" + )] + // 155 * 7 = 1085 + #[case::unsigned_normal(false, "10011011", "111", "0000010000111101")] + // 54 * 4234 = 228636 + #[case::unsigned_normal(false, "00110110", "0001000010001010", "00110111110100011100")] + // 37738 + 4365 = 99938 + #[case::unsigned_overflow(false, "1001001101101010", "0001000100001101", "00011000011001100010")] + fn mul(#[case] signed: bool, #[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + run_binary_cell_case_signed!(Mul, signed, a, b, expected); + } + + #[rstest] + // -37738 = 27798 + #[case::unsigned_normal(false, "1001001101101010", "0110110010010110")] + // -37738 = -37738 + #[case::signed_normal(true, "001001001101101010", "11110110110010010110")] + // -(-27798) = 27798 + #[case::signed_normal(true, "1001001101101010", "0110110010010110")] + fn negate(#[case] signed: bool, #[case] a: BitVec, #[case] expected: BitVec) { + run_unary_cell_case_signed!(Negate, signed, a, expected); + } + + #[rstest] + fn not_equal() { + println!("TODO") + } + #[rstest] + fn sub() { + println!("TODO") + } +} diff --git a/crates/arbolta/src/cell/simlib/bool_ops.rs b/crates/arbolta/src/cell/simlib/bool_ops.rs new file mode 100644 index 0000000..930c579 --- /dev/null +++ b/crates/arbolta/src/cell/simlib/bool_ops.rs @@ -0,0 +1,82 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use std::ops::{BitAnd, BitOr, BitXor}; + +use super::*; +use crate::{bit::BitVec, signal::Signals}; +use derive_more::Constructor; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Constructor, Serialize, Deserialize)] +pub struct Not { + signed: bool, + a_nets: Box<[usize]>, + y_nets: Box<[usize]>, +} + +impl CellFn for Not { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + let a = bits_from_nets_pad(self.signed, signals, &self.a_nets, self.y_nets.len()); + + self + .y_nets + .iter() + .zip(a) + .for_each(|(&n, b)| signals.set_net(n, !b)); + } + + fn reset(&mut self) {} +} + +define_arithmetic_cell!(&["$and"], ProcAnd { a, b }, y, a.bitand(b)); +define_arithmetic_cell!(&["$or"], ProcOr { a, b }, y, a.bitor(b)); +define_arithmetic_cell!(&["$xor"], ProcXor { a, b }, y, a.bitxor(b)); + +#[cfg(test)] +mod tests { + use super::*; + use crate::cell::test_helpers::*; + use rstest::rstest; + + #[rstest] + #[case(false, "1101", "110010")] + #[case(false, "1010", "110101")] + #[case(false, "0110", "111001")] + #[case(false, "11011110", "100001")] + #[case(false, "11111101", "000010")] + #[case(false, "1", "0")] + #[case(false, "0", "1")] + #[case(false, "1111", "0000")] + #[case(false, "0000", "1111")] + #[case(true, "1101", "000010")] + #[case(true, "1010", "000101")] + #[case(true, "0110", "111001")] + #[case(true, "11011110", "100001")] + #[case(true, "11111101", "000010")] + #[case(true, "1", "0")] + #[case(true, "0", "1")] + #[case(true, "1111", "0000")] + #[case(true, "0000", "1111")] + fn not(#[case] signed: bool, #[case] a: BitVec, #[case] expected: BitVec) { + run_unary_cell_case_signed!(Not, signed, a, expected); + } + + #[rstest] + #[case(false, "1111", "1111", "1111")] + #[case(false, "0000", "1111", "0000")] + fn and(#[case] signed: bool, #[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + run_binary_cell_case_signed!(ProcAnd, signed, a, b, expected); + } + + #[rstest] + fn or() { + println!("TODO") + } + + #[rstest] + fn xor() { + println!("TODO") + } +} diff --git a/crates/arbolta/src/cell/simlib/logic_reduce_ops.rs b/crates/arbolta/src/cell/simlib/logic_reduce_ops.rs new file mode 100644 index 0000000..641d68c --- /dev/null +++ b/crates/arbolta/src/cell/simlib/logic_reduce_ops.rs @@ -0,0 +1,122 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use super::*; +use crate::{bit::Bit, signal::Signals}; +use derive_more::Constructor; +use serde::{Deserialize, Serialize}; + +macro_rules! define_reduce_cell { + ($rtl_names:expr, $cell_type:ident { $($in_netn:ident),* $(,)?}, $out_net:ident, $op:tt, $body:expr) => { + #[derive(Debug, Clone, Constructor, Serialize, Deserialize)] + pub struct $cell_type { + $( + $in_netn: Box<[usize]>, + )* + + $out_net: Box<[usize]> + } + + impl CellFn for $cell_type { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + $( + let $in_netn: Bit = self + .$in_netn + .iter() + .fold(Bit::ZERO, |acc, &n| acc $op signals.get_net(n)); + )* + + signals.set_net(self.$out_net[0], $body ); + } + + fn reset(&mut self) {} + } + + paste! { + inventory::submit! {CellRegistration::new($rtl_names, + |connections: &BTreeMap<&str, Box<[usize]>>, _parameters: &BTreeMap<&str, usize>| { + if env::var("ARBOLTA_DEBUG").is_ok() { + println!("Parsing connections: {:#?}", connections); + } + + $cell_type::new( + $( + connections[stringify!([<$in_netn:upper>])].clone(), + )* + connections[stringify!([<$out_net:upper>])].clone() + ).into() + })} + } + }; +} + +define_reduce_cell!(&["$reduce_and"], ReduceAnd { a }, y, &, a); +define_reduce_cell!(&["$reduce_or", "$reduce_bool"], ReduceOr { a }, y, |, a); +define_reduce_cell!(&["$logic_and"], LogicAnd { a, b }, y, |, a & b); +define_reduce_cell!(&["$logic_not"], LogicNot { a }, y, |, !a); +define_reduce_cell!(&["$logic_or"], LogicOr { a, b }, y, |, a | b); + +#[cfg(test)] +mod tests { + use super::*; + use crate::bit::BitVec; + use crate::cell::test_helpers::*; + use rstest::rstest; + + #[rstest] + #[case("0", "0")] + #[case("00000000", "0000000")] + #[case("10000000", "0000001")] + #[case("1", "0000001")] + #[case("1111111", "01")] + #[case("1010100", "01")] + fn reduce_or(#[case] a: BitVec, #[case] expected: BitVec) { + run_unary_cell_case!(ReduceOr, a, expected); + } + + #[rstest] + fn reduce_and() { + println!("TODO") + } + + #[rstest] + #[case("0", "0", "0")] + #[case("0", "1", "0")] + #[case("1", "0", "0")] + #[case("1", "1", "1")] + #[case("00000000", "0000000", "0000")] + #[case("10000000", "0000001", "0001")] + #[case("1", "0000001", "01")] + #[case("1111111", "01", "01")] + #[case("1010100", "0000", "00000")] + fn logic_and(#[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + run_binary_cell_case!(LogicAnd, a, b, expected); + } + + #[rstest] + #[case("0", "1")] + #[case("1", "0")] + #[case("00000000", "0000001")] + #[case("10000000", "0000000")] + #[case("1", "0000000")] + #[case("1111111", "00")] + #[case("1010100", "00")] + fn logic_not(#[case] a: BitVec, #[case] expected: BitVec) { + run_unary_cell_case!(LogicNot, a, expected); + } + + #[rstest] + #[case("0", "0", "0")] + #[case("0", "1", "1")] + #[case("1", "0", "1")] + #[case("1", "1", "1")] + #[case("00000000", "0000000", "0000")] + #[case("10000000", "0000001", "0001")] + #[case("1", "0000001", "01")] + #[case("1111111", "01", "01")] + #[case("1010100", "0000", "00001")] + fn logic_or(#[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + run_binary_cell_case!(LogicOr, a, b, expected); + } +} diff --git a/crates/arbolta/src/cell/simlib/mod.rs b/crates/arbolta/src/cell/simlib/mod.rs new file mode 100644 index 0000000..69ed17b --- /dev/null +++ b/crates/arbolta/src/cell/simlib/mod.rs @@ -0,0 +1,264 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use super::{Cell, CellFn, CellRegistration}; +use crate::{ + bit::{Bit, BitVec}, + signal::Signals, +}; +use paste::paste; +use std::{collections::BTreeMap, env}; +mod arithmetic; +mod bool_ops; +mod logic_reduce_ops; +mod registers; +mod shift_ops; +mod various; + +#[inline(always)] +fn bits_from_nets(signals: &mut Signals, nets: &[usize]) -> Vec { + nets.iter().map(|&n| signals.get_net(n)).collect() +} + +#[inline(always)] +fn bits_from_nets_pad( + signed: bool, + signals: &mut Signals, + nets: &[usize], + out_size: usize, +) -> Vec { + let mut bits = bits_from_nets(signals, nets); + if bits.len() < out_size { + let sign_bit_set = bits.last().is_some_and(|&b| b.into()); + let pad_bit: Bit = (signed && sign_bit_set).into(); + let pad_size = out_size - bits.len(); + + bits.extend(std::iter::repeat_n(pad_bit, pad_size)); + } + + bits +} + +#[inline(always)] +fn copy_nets(signals: &mut Signals, src_nets: &[usize], dst_nets: &[usize]) { + src_nets.iter().zip(dst_nets.iter()).for_each(|(src, dst)| { + signals.set_net(*dst, signals.get_net(*src)); + }) +} + +#[inline(always)] +fn copy_bits<'a>( + signals: &mut Signals, + dst_nets: &[usize], + bits: impl IntoIterator, +) { + dst_nets + .iter() + .zip(bits) + .for_each(|(&n, b)| signals.set_net(n, *b)); +} + +#[macro_export] +macro_rules! define_arithmetic_cell { + ($rtl_names:expr, $cell_type:ident { $($in_netn:ident),* $(,)?}, $out_net:ident, $body:expr) => { + #[derive(Debug, Clone, Constructor, Serialize, Deserialize)] + pub struct $cell_type { + pub signed: bool, + + $( + $in_netn: Box<[usize]>, + )* + + $out_net: Box<[usize]> + } + + impl CellFn for $cell_type { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + $( + let $in_netn = BitVec::from(bits_from_nets(signals, &self.$in_netn)); + )* + + let output_size = self.$out_net.len(); + + let $out_net: BitVec = if self.signed { + if output_size <= 64 { + let ($($in_netn,)*) = ($($in_netn.to_int::(),)*); + BitVec::from_int( $body as i64, Some(output_size)) + } else { + let ($($in_netn,)*) = ($($in_netn.to_int::(),)*); + BitVec::from_int( $body as i128, Some(output_size)) + } + } else { + if output_size <= 64 { + let ($($in_netn,)*) = ($($in_netn.to_int::(),)*); + BitVec::from_int( $body as u64, Some(output_size)) + } else { + let ($($in_netn,)*) = ($($in_netn.to_int::(),)*); + BitVec::from_int( $body as u128, Some(output_size)) + } + }; + + copy_bits(signals, &self.$out_net, &$out_net); + } + + fn reset(&mut self) {} + } + + paste! { + inventory::submit! {CellRegistration::new($rtl_names, + |connections: &BTreeMap<&str, Box<[usize]>>, parameters: &BTreeMap<&str, usize>| { + if env::var("ARBOLTA_DEBUG").is_ok() { + println!("Parsing connections: {:#?}", connections); + } + + let mut signed = false; + $( + if let Some(&net_signed) = parameters.get(stringify!([<$in_netn:upper _SIGNED>])) { + signed |= (net_signed != 0); + } + )* + + $cell_type::new( + signed, + $( + connections[stringify!([<$in_netn:upper>])].clone(), + )* + connections[stringify!([<$out_net:upper>])].clone() + ).into() + })} + } + }; +} + +#[allow(unused)] +pub(crate) use define_arithmetic_cell; + +// Re-export +pub use arithmetic::*; +pub use bool_ops::*; +pub use logic_reduce_ops::*; +pub use registers::*; +pub use shift_ops::*; +pub use various::*; + +// TODO: clean up temp functions +fn make_not( + connections: &BTreeMap<&str, Box<[usize]>>, + parameters: &BTreeMap<&str, usize>, +) -> Cell { + Not::new( + parameters["A_SIGNED"] != 0, + connections["A"].clone(), + connections["Y"].clone(), + ) + .into() +} + +fn make_pos( + connections: &BTreeMap<&str, Box<[usize]>>, + parameters: &BTreeMap<&str, usize>, +) -> Cell { + Pos::new( + parameters["A_SIGNED"] != 0, + connections["A"].clone(), + connections["Y"].clone(), + ) + .into() +} + +fn make_dff( + connections: &BTreeMap<&str, Box<[usize]>>, + parameters: &BTreeMap<&str, usize>, +) -> Cell { + Reg::new( + (parameters["CLK_POLARITY"] != 0).into(), + connections["CLK"][0], + connections["D"].clone(), + connections["Q"].clone(), + ) + .into() +} + +fn make_aldff( + connections: &BTreeMap<&str, Box<[usize]>>, + parameters: &BTreeMap<&str, usize>, +) -> Cell { + DffAsyncLoad::new( + (parameters["CLK_POLARITY"] != 0).into(), + (parameters["ALOAD_POLARITY"] != 0).into(), + connections["CLK"][0], + connections["ALOAD"][0], + connections["AD"].clone(), + connections["D"].clone(), + connections["Q"].clone(), + ) + .into() +} + +fn make_adffe( + connections: &BTreeMap<&str, Box<[usize]>>, + parameters: &BTreeMap<&str, usize>, +) -> Cell { + let reset_val = BitVec::from_int(parameters["ARST_VALUE"], Some(parameters["WIDTH"])); + + DffAsyncResetEnable::new( + (parameters["CLK_POLARITY"] != 0).into(), + (parameters["EN_POLARITY"] != 0).into(), + (parameters["ARST_POLARITY"] != 0).into(), + reset_val.bits.into(), + connections["CLK"][0], + connections["ARST"][0], + connections["EN"][0], + connections["D"].clone(), + connections["Q"].clone(), + ) + .into() +} + +fn make_mux( + connections: &BTreeMap<&str, Box<[usize]>>, + _parameters: &BTreeMap<&str, usize>, +) -> Cell { + Mux::new( + connections["S"][0], + connections["A"].clone(), + connections["B"].clone(), + connections["Y"].clone(), + ) + .into() +} + +fn make_bmux( + connections: &BTreeMap<&str, Box<[usize]>>, + _parameters: &BTreeMap<&str, usize>, +) -> Cell { + BMux::new( + connections["S"].clone(), + connections["A"].clone(), + connections["Y"].clone(), + ) + .into() +} + +fn make_pmux( + connections: &BTreeMap<&str, Box<[usize]>>, + _parameters: &BTreeMap<&str, usize>, +) -> Cell { + PMux::new( + connections["S"].clone(), + connections["A"].clone(), + connections["B"].clone(), + connections["Y"].clone(), + ) + .into() +} + +inventory::submit! {CellRegistration::new(&["$not"], make_not)} +inventory::submit! {CellRegistration::new(&["$pos"], make_pos)} +inventory::submit! {CellRegistration::new(&["$dff"], make_dff)} +inventory::submit! {CellRegistration::new(&["$aldff"], make_aldff)} +inventory::submit! {CellRegistration::new(&["$adffe"], make_adffe)} +inventory::submit! {CellRegistration::new(&["$mux"], make_mux)} +inventory::submit! {CellRegistration::new(&["$bmux"], make_bmux)} +inventory::submit! {CellRegistration::new(&["$pmux"], make_pmux)} diff --git a/crates/arbolta/src/cell/simlib/registers.rs b/crates/arbolta/src/cell/simlib/registers.rs new file mode 100644 index 0000000..5afb83c --- /dev/null +++ b/crates/arbolta/src/cell/simlib/registers.rs @@ -0,0 +1,228 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use super::{CellFn, copy_nets}; +use crate::{bit::Bit, cell::simlib::copy_bits, signal::Signals}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, derive_new::new)] +pub struct Reg { + pub polarity: Bit, + pub clock_net: usize, + pub data_in_nets: Box<[usize]>, + pub data_out_nets: Box<[usize]>, + #[new(default)] + pub last_clock: Bit, +} + +impl CellFn for Reg { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + let clock = signals.get_net(self.clock_net); + + if clock == self.polarity && self.last_clock == !self.polarity { + copy_nets(signals, &self.data_in_nets, &self.data_out_nets); + } + + self.last_clock = clock; + } + + fn reset(&mut self) { + self.last_clock = !self.polarity; + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, derive_new::new)] +pub struct DffAsyncLoad { + clock_polarity: Bit, + load_polarity: Bit, + clock_net: usize, + async_load_net: usize, + async_data_in_nets: Box<[usize]>, + data_in_nets: Box<[usize]>, + data_out_nets: Box<[usize]>, + #[new(default)] + last_clock: Bit, + #[new(default)] + last_load: Bit, +} + +impl CellFn for DffAsyncLoad { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + let clock = signals.get_net(self.clock_net); + let load = signals.get_net(self.async_load_net); + + let pos_clock = clock == self.clock_polarity; + let pos_load = load == self.load_polarity; + let clock_rising = pos_clock && self.last_clock == !self.clock_polarity; + let load_rising = pos_load && self.last_load == !self.load_polarity; + + if clock_rising || load_rising { + if pos_load { + copy_nets(signals, &self.async_data_in_nets, &self.data_out_nets); + } else { + copy_nets(signals, &self.data_in_nets, &self.data_out_nets); + } + } + + self.last_clock = clock; + self.last_load = load; + } + + fn reset(&mut self) { + self.last_clock = !self.clock_polarity; + self.last_load = !self.load_polarity; + } +} + +#[allow(clippy::too_many_arguments)] +#[derive(Debug, Clone, Serialize, Deserialize, derive_new::new)] +pub struct DffAsyncResetEnable { + clock_polarity: Bit, + enable_polarity: Bit, + reset_polarity: Bit, + reset_val: Box<[Bit]>, + clock_net: usize, + reset_net: usize, + enable_net: usize, + data_in_nets: Box<[usize]>, + data_out_nets: Box<[usize]>, + #[new(default)] + last_clock: Bit, + #[new(default)] + last_reset: Bit, +} + +impl CellFn for DffAsyncResetEnable { + fn eval(&mut self, signals: &mut Signals) { + let clock = signals.get_net(self.clock_net); + let reset = signals.get_net(self.reset_net); + let enable = signals.get_net(self.enable_net); + + let pos_clock = clock == self.clock_polarity; + let pos_reset = reset == self.reset_polarity; + let clock_rising = pos_clock && self.last_clock == !self.clock_polarity; + let reset_rising = pos_reset && self.last_reset == !self.reset_polarity; + + if clock_rising || reset_rising { + if pos_reset { + copy_bits(signals, &self.data_out_nets, &self.reset_val); + } else if enable == self.enable_polarity { + copy_nets(signals, &self.data_in_nets, &self.data_out_nets); + } + } + + self.last_clock = clock; + self.last_reset = reset; + } + + fn reset(&mut self) { + self.last_clock = !self.clock_polarity; + self.last_reset = !self.reset_polarity; + } +} + +#[cfg(test)] +mod tests { + use super::super::{bits_from_nets, copy_bits}; + use super::*; + use crate::{bit::BitVec, cell::test_helpers::*}; + use rstest::rstest; + + #[rstest] + #[case::zero(Bit::ONE, "000000000000")] // 0 + #[case::one(Bit::ONE, "000000000001")] // 1 + #[case(Bit::ONE, "1101111001101100")] // 56940 + #[case(Bit::ZERO, "000000000000")] // 0 + #[case(Bit::ZERO, "000000000001")] // 1 + #[case(Bit::ZERO, "1101111001101100")] // 56940 + fn reg(#[case] polarity: Bit, #[case] data_in: BitVec) { + let reg_size = data_in.len(); + let nets = allocate_nets(Some(1), &[&data_in, &data_in]); + + let clock_net: usize = 0; + let (data_in_nets, data_out_nets) = (&nets[0], &nets[1]); + + let mut signals = Signals::new(data_out_nets.last().unwrap() + 1); + let mut cell = Reg::new( + polarity, + clock_net, + data_in_nets.clone(), + data_out_nets.clone(), + ); + + signals.set_net(clock_net, !polarity); // Reset + cell.eval(&mut signals); + let mut actual = BitVec::from(bits_from_nets(&mut signals, data_out_nets)); + assert_eq!(actual.to_int::(), 0); + assert_eq!(cell.last_clock, !polarity); + + copy_bits(&mut signals, data_in_nets, &data_in); + cell.eval(&mut signals); + actual = BitVec::from(bits_from_nets(&mut signals, data_out_nets)); + assert_eq!(actual.to_int::(), 0); + assert_eq!(cell.last_clock, !polarity); + + signals.set_net(clock_net, polarity); // Rising edge + cell.eval(&mut signals); + actual = BitVec::from(bits_from_nets(&mut signals, data_out_nets)); + assert_eq!(actual, data_in); + assert_eq!(cell.last_clock, polarity); + + signals.set_net(clock_net, !polarity); // Falling edge + cell.eval(&mut signals); + actual = BitVec::from(bits_from_nets(&mut signals, data_out_nets)); + assert_eq!(actual, data_in); + assert_eq!(cell.last_clock, !polarity); + + copy_bits(&mut signals, data_in_nets, &vec![Bit::ZERO; reg_size]); // Zero + cell.eval(&mut signals); + actual = BitVec::from(bits_from_nets(&mut signals, data_out_nets)); + assert_eq!(actual, data_in); + assert_eq!(cell.last_clock, !polarity); + + signals.set_net(clock_net, polarity); // Rising edge + cell.eval(&mut signals); + actual = BitVec::from(bits_from_nets(&mut signals, data_out_nets)); + assert_eq!(actual, BitVec::from(vec![Bit::ZERO; reg_size])); + assert_eq!(cell.last_clock, polarity); + } + + #[rstest] + #[case::zero(Bit::ONE, Bit::ZERO, "000000000000")] // 0 + #[case::zero(Bit::ONE, Bit::ONE, "000000000000")] // 0 + #[case::one(Bit::ONE, Bit::ZERO, "000000000001")] // 1 + #[case::one(Bit::ONE, Bit::ONE, "000000000001")] // 1 + #[case(Bit::ONE, Bit::ZERO, "1101111001101100")] // 56940 + #[case(Bit::ONE, Bit::ONE, "1101111001101100")] // 56940 + #[case(Bit::ZERO, Bit::ZERO, "000000000000")] // 0 + #[case(Bit::ZERO, Bit::ONE, "000000000000")] // 0 + #[case(Bit::ZERO, Bit::ZERO, "000000000001")] // 1 + #[case(Bit::ZERO, Bit::ONE, "000000000001")] // 1 + #[case(Bit::ZERO, Bit::ZERO, "1101111001101100")] // 56940 + #[case(Bit::ZERO, Bit::ONE, "1101111001101100")] // 56940 + + fn aldff(#[case] clock_polarity: Bit, #[case] load_polarity: Bit, #[case] data_in: BitVec) { + let _reg_size = data_in.len(); + let nets = allocate_nets(Some(2), &[&data_in, &data_in, &data_in]); + let (clock_net, load_net) = (0_usize, 1_usize); + let (data_in_nets, async_data_in_nets, data_out_nets) = (&nets[0], &nets[1], &nets[2]); + + let mut signals = Signals::new(data_out_nets.last().unwrap() + 1); + let mut cell = DffAsyncLoad::new( + clock_polarity, + load_polarity, + clock_net, + load_net, + async_data_in_nets.clone(), + data_in_nets.clone(), + data_out_nets.clone(), + ); + + cell.eval(&mut signals); + let actual = BitVec::from(bits_from_nets(&mut signals, data_out_nets)); + assert_eq!(actual.to_int::(), 0); // Should start w/ 0 + // TODO: Check other cases + } +} diff --git a/crates/arbolta/src/cell/simlib/shift_ops.rs b/crates/arbolta/src/cell/simlib/shift_ops.rs new file mode 100644 index 0000000..9c1f219 --- /dev/null +++ b/crates/arbolta/src/cell/simlib/shift_ops.rs @@ -0,0 +1,98 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use super::*; +use crate::{bit::BitVec, signal::Signals}; +use derive_more::Constructor; +use serde::{Deserialize, Serialize}; + +macro_rules! define_shift_cell { + ($rtl_names:expr, $cell_type:ident { $op_net:ident, $shift_net:ident }, $out_net:ident, $body:expr) => { + #[derive(Debug, Clone, Constructor, Serialize, Deserialize)] + pub struct $cell_type { + pub signed: bool, + $op_net: Box<[usize]>, + $shift_net: Box<[usize]>, + $out_net: Box<[usize]>, + } + + impl CellFn for $cell_type { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + let $op_net = BitVec::from(bits_from_nets(signals, &self.$op_net)); + let $shift_net = BitVec::from(bits_from_nets(signals, &self.$shift_net)).to_int::(); + let output_size = self.$out_net.len(); + + let $out_net: BitVec = if self.signed { + if output_size <= 64 { + let $op_net = $op_net.to_int::(); + BitVec::from_int($body as i64, Some(output_size)) + } else { + let $op_net = $op_net.to_int::(); + BitVec::from_int($body as i128, Some(output_size)) + } + } else { + if output_size <= 64 { + let $op_net = $op_net.to_int::(); + BitVec::from_int($body as u64, Some(output_size)) + } else { + let $op_net = $op_net.to_int::(); + BitVec::from_int($body as u128, Some(output_size)) + } + }; + + copy_bits(signals, &self.$out_net, &$out_net); + } + + fn reset(&mut self) {} + } + + paste! { + inventory::submit! {CellRegistration::new($rtl_names, + |connections: &BTreeMap<&str, Box<[usize]>>, parameters: &BTreeMap<&str, usize>| { + if env::var("ARBOLTA_DEBUG").is_ok() { + println!("Parsing connections: {:#?}", connections); + } + + let signed = match parameters.get(stringify!([<$op_net:upper _SIGNED>])) { + Some(&net_signed) => net_signed != 0, + None => false + }; + + $cell_type::new( + signed, + connections[stringify!([<$op_net:upper>])].clone(), + connections[stringify!([<$shift_net:upper>])].clone(), + connections[stringify!([<$out_net:upper>])].clone() + ).into() + })} + } + }; +} +define_shift_cell!(&["$shl"], Shl { a, b }, y, a.wrapping_shl(b)); +define_shift_cell!(&["$shr"], Shr { a, b }, y, a.wrapping_shr(b)); + +#[cfg(test)] +mod tests { + use super::*; + use crate::cell::test_helpers::*; + use rstest::rstest; + + #[rstest] + #[case(false, "10011011", "0", "0000000010011011")] // 155 << 0 + #[case(true, "10011011", "0", "1111111110011011")] // -101 << 0 + #[case(false, "10011011", "111", "0100110110000000")] // 155 << 7 + #[case(true, "10011011", "111", "1100110110000000")] // -101 << 7 + fn shl(#[case] signed: bool, #[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + run_binary_cell_case_signed!(Shl, signed, a, b, expected); + } + + #[rstest] + #[case(false, "10011011", "0", "0000000010011011")] // 155 >> 0 + #[case(true, "10011011", "0", "1111111110011011")] // -101 >> 0 + #[case(false, "10011011", "111", "0000000000000001")] // 155 >> 7 + #[case(true, "10011011", "111", "1111111111111111")] // -101 >> 7 + fn shr(#[case] signed: bool, #[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + run_binary_cell_case_signed!(Shr, signed, a, b, expected); + } +} diff --git a/crates/arbolta/src/cell/simlib/various.rs b/crates/arbolta/src/cell/simlib/various.rs new file mode 100644 index 0000000..2e0fa11 --- /dev/null +++ b/crates/arbolta/src/cell/simlib/various.rs @@ -0,0 +1,154 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use super::{CellFn, bits_from_nets_pad, copy_bits, copy_nets}; +use crate::{ + bit::{Bit, BitVec}, + cell::simlib::bits_from_nets, + signal::Signals, +}; +use derive_more::Constructor; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Constructor, Serialize, Deserialize)] +pub struct Pos { + signed: bool, + a_nets: Box<[usize]>, + y_nets: Box<[usize]>, +} + +impl CellFn for Pos { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + // Passthrough with padding + let a = bits_from_nets_pad(self.signed, signals, &self.a_nets, self.y_nets.len()); + copy_bits(signals, &self.y_nets, &a); + } + + fn reset(&mut self) {} +} + +#[derive(Debug, Clone, Serialize, Deserialize, Constructor)] +pub struct Mux { + pub select_net: usize, + pub a_nets: Box<[usize]>, + pub b_nets: Box<[usize]>, + pub y_nets: Box<[usize]>, +} + +impl CellFn for Mux { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + let src_nets = match signals.get_net(self.select_net) { + Bit::ZERO => &self.a_nets, + Bit::ONE => &self.b_nets, + }; + copy_nets(signals, src_nets, &self.y_nets); + } + + fn reset(&mut self) {} +} + +#[derive(Debug, Clone, Serialize, Deserialize, Constructor)] +pub struct BMux { + select_nets: Box<[usize]>, + a_nets: Box<[usize]>, + y_nets: Box<[usize]>, +} + +// "Selects between 'slices' of A where each value of S corresponds to a unique" +impl CellFn for BMux { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + let select = BitVec::from(bits_from_nets(signals, &self.select_nets)); + let start_net = select.to_int::() * self.y_nets.len(); + let end_net = start_net + self.y_nets.len(); + + // TODO: Don't read all bits + let a = bits_from_nets(signals, &self.a_nets); + (start_net..end_net) + .zip(a) + .for_each(|(n, b)| signals.set_net(n, b)); + } + + fn reset(&mut self) {} +} +// "Selects between 'slices' of B where each slice corresponds to a single bit +// of S. Outputs A when all bits of S are low." +#[derive(Debug, Clone, Serialize, Deserialize, Constructor)] +pub struct PMux { + select_nets: Box<[usize]>, + a_nets: Box<[usize]>, // output when S all low + b_nets: Box<[usize]>, // slices source + y_nets: Box<[usize]>, // slice size +} + +impl CellFn for PMux { + #[inline] + fn eval(&mut self, signals: &mut Signals) { + // Should be power of 2? + // 0, 2, 4, 8 + let select = BitVec::from(bits_from_nets(signals, &self.select_nets)).to_int::(); + // let src_nets = &self.a_nets; + if select == 0 { + let a = bits_from_nets(signals, &self.a_nets); + copy_bits(signals, &self.y_nets, &a); + } else { + let start_net = (select.ilog2() as usize) * self.y_nets.len(); + let end_net = start_net + self.y_nets.len(); + + // TODO: Don't read all bits + let a = bits_from_nets(signals, &self.b_nets); + (start_net..end_net) + .zip(a) + .for_each(|(n, b)| signals.set_net(n, b)); + } + } + + fn reset(&mut self) {} +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cell::test_helpers::*; + use rstest::rstest; + + #[rstest] + fn pos() { + println!("TODO"); + } + + #[rstest] + #[case(Bit::ZERO, "000", "001", "000")] + #[case(Bit::ONE, "000", "001", "001")] + #[case(Bit::ZERO, "111", "000", "111")] + #[case(Bit::ONE, "111", "000", "000")] + fn mux(#[case] select: Bit, #[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + let nets = allocate_nets(Some(1), &[&a, &b, &expected]); + + let select_net: usize = 0; + let (a_nets, b_nets, y_nets) = (&nets[0], &nets[1], &nets[2]); + let mut signals = Signals::new(y_nets.last().unwrap() + 1); + let mut cell = Mux::new(select_net, a_nets.clone(), b_nets.clone(), y_nets.clone()); + + signals.set_net(select_net, select); + copy_bits(&mut signals, a_nets, &a); + copy_bits(&mut signals, b_nets, &b); + + cell.eval(&mut signals); + let actual = BitVec::from(bits_from_nets(&mut signals, y_nets)); + + assert_eq!(actual, expected); + } + + #[rstest] + fn bmux() { + println!("TODO"); + } + + #[rstest] + fn pmux() { + println!("TODO"); + } +} diff --git a/crates/arbolta/src/cell/test_helpers.rs b/crates/arbolta/src/cell/test_helpers.rs new file mode 100644 index 0000000..b0d7be4 --- /dev/null +++ b/crates/arbolta/src/cell/test_helpers.rs @@ -0,0 +1,182 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use crate::bit::BitVec; + +#[macro_export] +macro_rules! make_unary_wires { + ($a:expr, $y:expr) => {{ + let a_size = $a.bits.len(); + let y_size = $y.bits.len(); + let a_nets: Vec = (0..a_size).collect(); + let y_nets: Vec = (a_size..a_size + y_size).collect(); + (a_nets, y_nets) + }}; +} + +#[allow(unused)] +pub(crate) use make_unary_wires; + +#[macro_export] +macro_rules! make_binary_wires { + ($a:expr, $b:expr, $y:expr) => {{ + let a_size = $a.bits.len(); + let b_size = $b.bits.len(); + let y_size = $y.bits.len(); + let a_nets: Vec = (0..a_size).collect(); + let b_nets: Vec = (a_size..a_size + b_size).collect(); + let y_nets: Vec = (a_size + b_size..a_size + b_size + y_size).collect(); + (a_nets, b_nets, y_nets) + }}; +} + +#[allow(unused)] +pub(crate) use make_binary_wires; + +#[macro_export] +macro_rules! run_unary_cell_case_signed { + ($cell:ty, $signed:expr, $a:expr, $expected:expr) => {{ + let (a_nets, y_nets) = make_unary_wires!($a, $expected); + let mut signals = Signals::new(y_nets.last().unwrap() + 1); + + // Set inputs + a_nets + .iter() + .enumerate() + .for_each(|(i, n)| signals.set_net(*n, $a.bits[i])); + + // Create cell and evaluate + let mut cell: $cell = <$cell>::new($signed, a_nets.into(), y_nets.clone().into()); + cell.eval(&mut signals); + + // Get outputs + let actual: $crate::bit::BitVec = y_nets + .iter() + .map(|&i| signals.get_net(i)) + .collect::>() + .into(); + + assert_eq!(actual, $expected); + }}; +} + +#[allow(unused)] +pub(crate) use run_unary_cell_case_signed; + +#[macro_export] +macro_rules! run_unary_cell_case { + ($cell:ty, $a:expr, $expected:expr) => {{ + let (a_nets, y_nets) = make_unary_wires!($a, $expected); + let mut signals = Signals::new(y_nets.last().unwrap() + 1); + + // Set inputs + a_nets + .iter() + .enumerate() + .for_each(|(i, n)| signals.set_net(*n, $a.bits[i])); + + // Create cell and evaluate + let mut cell: $cell = <$cell>::new(a_nets.into(), y_nets.clone().into()); + cell.eval(&mut signals); + + // Get outputs + let actual: $crate::bit::BitVec = y_nets + .iter() + .map(|&i| signals.get_net(i)) + .collect::>() + .into(); + + assert_eq!(actual, $expected); + }}; +} + +#[allow(unused)] +pub(crate) use run_unary_cell_case; + +#[macro_export] +macro_rules! run_binary_cell_case { + ($cell:ty, $a:expr, $b:expr, $expected:expr) => {{ + let (a_nets, b_nets, y_nets) = make_binary_wires!($a, $b, $expected); + let mut signals = Signals::new(y_nets.last().unwrap() + 1); + + // Set inputs + a_nets + .iter() + .enumerate() + .for_each(|(i, n)| signals.set_net(*n, $a.bits[i])); + + b_nets + .iter() + .enumerate() + .for_each(|(i, n)| signals.set_net(*n, $b.bits[i])); + + // Create cell and evaluate + let mut cell: $cell = <$cell>::new(a_nets.into(), b_nets.into(), y_nets.clone().into()); + cell.eval(&mut signals); + + // Get outputs + let actual: $crate::bit::BitVec = y_nets + .iter() + .map(|&i| signals.get_net(i)) + .collect::>() + .into(); + + assert_eq!(actual, $expected); + }}; +} + +#[allow(unused)] +pub(crate) use run_binary_cell_case; + +#[macro_export] +macro_rules! run_binary_cell_case_signed { + ($cell:ty, $signed:expr, $a:expr, $b:expr, $expected:expr) => {{ + let (a_nets, b_nets, y_nets) = make_binary_wires!($a, $b, $expected); + let mut signals = Signals::new(y_nets.last().unwrap() + 1); + + // Set inputs + a_nets + .iter() + .enumerate() + .for_each(|(i, n)| signals.set_net(*n, $a.bits[i])); + + b_nets + .iter() + .enumerate() + .for_each(|(i, n)| signals.set_net(*n, $b.bits[i])); + + // Create cell and evaluate + let mut cell: $cell = + <$cell>::new($signed, a_nets.into(), b_nets.into(), y_nets.clone().into()); + cell.eval(&mut signals); + + // Get outputs + let actual: $crate::bit::BitVec = y_nets + .iter() + .map(|&i| signals.get_net(i)) + .collect::>() + .into(); + + assert_eq!(actual, $expected); + }}; +} + +#[allow(unused)] +pub(crate) use run_binary_cell_case_signed; + +#[allow(unused)] +pub fn allocate_nets(offset: Option, data: &[&BitVec]) -> Vec> { + let mut nets: Vec> = vec![]; + let offset = offset.unwrap_or(0); + + for bits in data { + let start: usize = match nets.last() { + Some(last) => last[last.len() - 1] + 1, + None => offset, + }; + + nets.push((start..start + bits.len()).collect()); + } + + nets +} diff --git a/crates/arbolta/src/hardware_module.rs b/crates/arbolta/src/hardware_module.rs new file mode 100644 index 0000000..7486fd4 --- /dev/null +++ b/crates/arbolta/src/hardware_module.rs @@ -0,0 +1,344 @@ +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use crate::{ + bit::{Bit, BitVec}, + cell::{Cell, CellError, CellFn, CellMapping}, + netlist_wrapper::NetlistWrapper, + port::{Port, PortDirection, PortError}, + signal::Signals, + yosys::{Netlist, TopoOrder}, +}; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, fmt::Debug}; +use thiserror::Error; + +#[derive(Default, Clone, Debug, Deserialize, Serialize)] //Decode, Encode +pub struct HardwareModule { + pub netlist: NetlistWrapper, + pub signals: Signals, + pub cells: Box<[Cell]>, + pub ports: HashMap, + pub clock_net: Option<(usize, Bit)>, // (net, polarity) + pub reset_net: Option<(usize, Bit)>, // (net, polarity) +} + +// TODO: Refactor these +#[derive(Debug, Error)] +pub enum ModuleError { + #[error("Missing top module")] + TopModule, + #[error("Cell `{0}` doesn't exist")] + MissingCell(String), + #[error("No modules given")] + MissingModule, + #[error("Module `{0}` missing from topological order")] + TopoOrder(String), + #[error(transparent)] + Cell(#[from] CellError), + #[error(transparent)] + Port(#[from] PortError), + #[error("No reset configured")] + MissingReset, + #[error("No clock configured")] + MissingClock, + #[error("Signal `{0}` doesn't exist")] + MissingSignal(String), + #[error("Net `{0}` doesn't exist")] + MissingNet(usize), + #[error("Port `{0}` doesn't exist")] + MissingPort(String), + #[error(transparent)] + Netlist(#[from] serde_json::Error), + #[error("Signal cannot be configured as both a reset and clock")] + DoubleAssign, +} + +#[derive(Clone, Debug, Copy)] +pub enum ToggleCount { + Rising, + Falling, + Total, +} + +impl HardwareModule { + pub fn new( + netlist: Netlist, + top_module: Option<&str>, + torder: TopoOrder, + hierarchy_separator: Option<&str>, + cell_mapping: Option<&CellMapping>, + ) -> Result { + let netlist = NetlistWrapper::new(netlist, top_module, torder, hierarchy_separator)?; + + let cells = netlist.build_cells(cell_mapping)?; + + let global_net_max: usize = netlist + .nets + .values() + .flatten() + .fold(0, |max, &x| std::cmp::max(max, x)); + + let mut signals = Signals::new(global_net_max + 1); + signals.set_constant(0, Bit::ZERO); + signals.set_constant(1, Bit::ONE); + + // type doesn't matter here... + let ports = netlist.find_module_ports::<&str>(None)?; + + Ok(Self { + netlist, + signals, + cells: cells.into(), + ports, + ..Default::default() + }) + } + + pub fn reset(&mut self) { + self.cells.iter_mut().for_each(|c| c.reset()); + self.signals.reset(); + self.signals.set_constant(0, Bit::ZERO); + self.signals.set_constant(1, Bit::ONE); + } + + // Eval until all signals have settled + pub fn eval(&mut self) { + loop { + self.signals.clear_dirty(); + self + .cells + .iter_mut() + .for_each(|cell| cell.eval(&mut self.signals)); + + if !self.signals.is_dirty() { + break; + } + } + } + + pub fn eval_clocked(&mut self, cycles: Option) -> Result<(), ModuleError> { + let Some((clock_net, polarity)) = self.clock_net else { + return Err(ModuleError::MissingClock); + }; + + let cycles = cycles.unwrap_or(1); + + for _ in 0..cycles { + self.eval(); + self.signals.set_net(clock_net, polarity); + self.eval(); + self.signals.set_net(clock_net, !polarity); + self.eval(); + } + + Ok(()) + } + + pub fn eval_reset_clocked(&mut self, cycles: Option) -> Result<(), ModuleError> { + let Some((reset_net, polarity)) = self.reset_net else { + return Err(ModuleError::MissingReset); + }; + + self.signals.set_net(reset_net, polarity); + self.eval_clocked(cycles)?; + self.signals.set_net(reset_net, !polarity); + self.eval(); + + Ok(()) + } + + pub fn stick_signal(&mut self, net: usize, value: Bit) -> Result<(), ModuleError> { + if net >= self.signals.size { + Err(ModuleError::MissingNet(net)) + } else { + self.signals.set_constant(net, value); + Ok(()) + } + } + + pub fn unstick_signal(&mut self, net: usize) -> Result<(), ModuleError> { + if net >= self.signals.size { + Err(ModuleError::MissingNet(net)) + } else { + self.signals.unset_constant(net); + Ok(()) + } + } + + // TODO: Fix + pub fn get_net_bits(&self, name: &str) -> Result { + let Some(nets) = self.get_net(name) else { + return Err(ModuleError::MissingPort(name.to_string())); + }; + + let bits: BitVec = nets + .iter() + .map(|idx| self.signals.get_net(*idx)) + .collect::>() + .into(); + + Ok(bits) + } + + pub fn get_net(&self, name: &str) -> Option<&[usize]> { + self.netlist.names_to_nets.get(name).map(|v| &**v) + } + + pub fn set_clock(&mut self, net: usize, polarity: Bit) -> Result<(), ModuleError> { + if net >= self.signals.size { + Err(ModuleError::MissingNet(net)) + } else if let Some((reset_net, _)) = self.reset_net + && reset_net == net + { + Err(ModuleError::DoubleAssign) + } else { + self.clock_net = Some((net, polarity)); + Ok(()) + } + } + + pub fn set_reset(&mut self, net: usize, polarity: Bit) -> Result<(), ModuleError> { + if net >= self.signals.size { + Err(ModuleError::MissingNet(net)) + } else if let Some((clock_net, _)) = self.clock_net + && clock_net == net + { + Err(ModuleError::DoubleAssign) + } else { + self.reset_net = Some((net, polarity)); + Ok(()) + } + } + + pub fn set_port_shape(&mut self, name: &str, shape: &[usize; 2]) -> Result<(), ModuleError> { + match self.ports.get_mut(name) { + Some(port) => Ok(port.set_shape(shape)?), + None => Err(ModuleError::MissingPort(name.to_string())), + } + } + + pub fn get_port_shape(&self, name: &str) -> Result<[usize; 2], ModuleError> { + match self.ports.get(name) { + Some(port) => Ok(port.get_shape()), + None => Err(ModuleError::MissingPort(name.to_string())), + } + } + + pub fn get_port_direction(&self, name: &str) -> Result { + match self.ports.get(name) { + Some(port) => Ok(port.direction.clone()), + None => Err(ModuleError::MissingPort(name.to_string())), + } + } + + pub fn get_port(&self, name: &str) -> Result { + let (Some(port), Some(nets)) = (self.ports.get(name), self.get_net(name)) else { + return Err(ModuleError::MissingPort(name.to_string())); + }; + + let mut bits: BitVec = nets + .iter() + .map(|idx| self.signals.get_net(*idx)) + .collect::>() + .into(); + bits.shape = port.shape; + + Ok(bits) + } + + pub fn set_port(&mut self, name: &str, vals: I) -> Result<(), ModuleError> + where + I: IntoIterator, + B: Into, + { + let (Some(_port), Some(nets)) = (self.ports.get(name), self.get_net(name)) else { + return Err(ModuleError::MissingPort(name.to_string())); + }; + + nets + .to_owned() + .iter() + .zip(vals.into_iter().map(Into::into)) + .for_each(|(net, b)| self.signals.set_net(*net, b)); + + Ok(()) + } + + // Returns ALL nets in design + pub fn get_submodule_nets(&self) -> HashMap<&Vec, HashMap<&str, &[usize]>> { + let mut global_module_nets = HashMap::new(); + for (net_id, nets) in &self.netlist.nets { + let module_nets: &mut HashMap<&str, &[usize]> = + global_module_nets.entry(&net_id.parents).or_default(); + + module_nets.insert(&net_id.name, nets); + } + + global_module_nets + } + + pub fn get_submodule_net_values(&self) -> HashMap<&Vec, HashMap<&str, BitVec>> { + let global_submodule_nets = self.get_submodule_nets(); + let mut global_net_values = HashMap::new(); + + for (parents, module_nets) in global_submodule_nets { + let submodule_net_values: &mut HashMap<&str, BitVec> = + global_net_values.entry(parents).or_default(); + + for (net_name, nets) in module_nets { + let bits: BitVec = nets + .iter() + .map(|idx| self.signals.get_net(*idx)) + .collect::>() + .into(); + + submodule_net_values.insert(net_name, bits); + } + } + + global_net_values + } + + pub fn get_submodule_toggles_by_net( + &self, + category: ToggleCount, + ) -> HashMap<&Vec, HashMap<&str, u64>> { + let global_submodule_nets = self.get_submodule_nets(); + + let toggle_fn = match category { + ToggleCount::Falling => Signals::get_toggles_falling, + ToggleCount::Rising => Signals::get_toggles_rising, + ToggleCount::Total => Signals::get_toggles_total, + }; + + let mut global_submodule_toggles = HashMap::new(); + for (parents, module_nets) in global_submodule_nets { + let submodule_toggles: &mut HashMap<&str, u64> = + global_submodule_toggles.entry(parents).or_default(); + + for (net_name, nets) in module_nets { + let toggles = nets + .iter() + .fold(0, |acc, &n| acc + toggle_fn(&self.signals, n)); + + submodule_toggles.insert(net_name, toggles); + } + } + + global_submodule_toggles + } + + pub fn get_submodule_toggles_total(&self, category: ToggleCount) -> HashMap<&Vec, u64> { + let submodule_toggles_by_net = self.get_submodule_toggles_by_net(category); + let mut submodule_toggles = HashMap::new(); + + for (parents, module_nets) in submodule_toggles_by_net { + let total_toggles = module_nets.values().sum(); + submodule_toggles.insert(parents, total_toggles); + } + + submodule_toggles + } +} diff --git a/crates/arbolta/src/lib.rs b/crates/arbolta/src/lib.rs index ecea90c..c29b1ea 100644 --- a/crates/arbolta/src/lib.rs +++ b/crates/arbolta/src/lib.rs @@ -1,8 +1,11 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding // SPDX-License-Identifier: MIT pub mod bit; pub mod cell; -pub mod module; +pub mod hardware_module; +pub mod netlist_wrapper; +pub mod port; pub mod signal; -pub mod synth; +pub mod yosys; diff --git a/crates/arbolta/src/module/design.rs b/crates/arbolta/src/module/design.rs deleted file mode 100644 index 1fcfc87..0000000 --- a/crates/arbolta/src/module/design.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use crate::bit::Bit; -use crate::cell::{CellError, CellLibrary}; -use crate::module::hardware_module::{HardwareModule, ModuleError}; -use crate::signal::SignalIndex; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::io; -use std::io::Write; -use thiserror::Error; - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Design { - pub module: HardwareModule, - pub clock: Option, - pub reset: Option, - pub cell_library: CellLibrary, -} - -#[derive(Debug, Error)] -pub enum DesignError { - #[error("{0}")] - ModuleError(#[from] ModuleError), - #[error("{0}")] - CellError(#[from] CellError), - #[error("{0}")] - IoError(#[from] io::Error), - #[error("{0}")] - FlexReaderError(#[from] flexbuffers::ReaderError), - #[error("{0}")] - DeserializeError(#[from] flexbuffers::DeserializationError), - #[error("{0}")] - SerializeError(#[from] flexbuffers::SerializationError), -} - -impl Design { - pub fn load(path: &str) -> Result { - let serialized = std::fs::read(path)?; - let reader = flexbuffers::Reader::get_root(serialized.as_slice())?; - Ok(Self::deserialize(reader)?) - } - - pub fn save(&self, path: &str) -> Result<(), DesignError> { - let mut serializer = flexbuffers::FlexbufferSerializer::new(); - self.serialize(&mut serializer)?; - let mut file_output = std::fs::File::create(path)?; - _ = file_output.write(serializer.view())?; - Ok(()) - } - - pub fn from_module(module: HardwareModule, cell_library: CellLibrary) -> Self { - Self { - module, - clock: None, - reset: None, - cell_library, - } - } - - pub fn set_clock(&mut self, name: &str) -> Result<(), DesignError> { - self.clock = Some(self.module.get_signal_idx(name)?); - Ok(()) - } - - pub fn set_reset(&mut self, name: &str) -> Result<(), DesignError> { - self.reset = Some(self.module.get_signal_idx(name)?); - Ok(()) - } - - pub fn eval(&mut self) { - self.module.eval(); - } - - pub fn eval_clocked(&mut self) -> Result<(), DesignError> { - let Some(clock) = self.clock else { - return Err(DesignError::ModuleError(ModuleError::MissingSignal( - "clock".to_string(), - ))); - }; - - // Can we do this deterministically? - self.module.eval(); - self.module.eval(); - self.module.eval(); - self.module.set_signal(clock, Bit::One)?; - self.module.eval(); - self.module.set_signal(clock, Bit::Zero)?; - self.module.eval(); - Ok(()) - } - - pub fn reset_clocked(&mut self) -> Result<(), DesignError> { - let Some(reset) = self.reset else { - return Err(DesignError::ModuleError(ModuleError::MissingSignal( - "reset".to_string(), - ))); - }; - - self.module.set_signal(reset, Bit::One)?; - self.eval_clocked()?; - self.module.set_signal(reset, Bit::Zero)?; - self.module.eval(); - - Ok(()) - } - - pub fn get_module_area(&self, name: &str) -> Result { - let breakdown = self.get_module_breakdown(name)?; - Ok(self.cell_library.get_cell_breakdown_area(&breakdown)?) - } - - pub fn get_module_breakdown(&self, name: &str) -> Result, DesignError> { - Ok(self.module.search_module_cell_breakdown(name)?) - } - - pub fn get_module_total_toggle_count(&self, name: &str) -> Result { - Ok(self.module.search_module_total_toggle_count(name)?) - } -} diff --git a/crates/arbolta/src/module/hardware_module.rs b/crates/arbolta/src/module/hardware_module.rs deleted file mode 100644 index 24cef76..0000000 --- a/crates/arbolta/src/module/hardware_module.rs +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use super::port::{Port, PortDirection, PortError}; -use crate::bit::{Bit, BitVec}; -use crate::cell::Cell; -use crate::signal::{AccessSignal, SignalIndex, SignalIndexMap, SignalList}; -use ndarray::{Array1, ArrayView1}; -use num_traits::PrimInt; -use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, HashMap, HashSet}; -use std::fmt::Debug; -use thiserror::Error; - -pub type PortMap = BTreeMap; - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub enum Component { - Cell(Cell), - Module(HardwareModule), -} - -pub type ComponentIndex = usize; -pub type ComponentIndexMap = BTreeMap; - -#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)] -pub struct HardwareModule { - pub name: String, - pub ports: PortMap, - pub signals: SignalList, - pub signal_map: SignalIndexMap, - pub components: Vec, - pub component_map: ComponentIndexMap, - pub input_connections: Vec<(SignalIndex, SignalIndex)>, - pub output_connections: Vec<(SignalIndex, SignalIndex)>, -} - -#[derive(Debug, Error)] -pub enum ModuleError { - #[error("module does not have port `{0}`")] - MissingPort(String), - #[error("error accessing port `{0}`: {1}")] - Port(String, PortError), - #[error("module does not have signal `{0}`")] - MissingSignal(String), - #[error("module does not have signal index `{0}`")] - MissingSignalIndex(SignalIndex), - #[error("module `{0}` does not exist")] - MissingModule(String), -} - -impl HardwareModule { - pub fn get_signal_idx(&self, name: &str) -> Result { - match self.signal_map.get(name) { - Some(idx) => Ok(*idx), - None => Err(ModuleError::MissingSignal(name.to_string())), - } - } - - pub fn set_signal(&mut self, idx: SignalIndex, val: Bit) -> Result<(), ModuleError> { - if idx > self.signals.len() { - Err(ModuleError::MissingSignalIndex(idx)) - } else { - self.signals[idx].set_value(val); - Ok(()) - } - } - - pub fn get_module_port_int( - &self, - path: Vec<&str>, - name: &str, - ) -> Result { - if path.is_empty() { - return self.get_port_int(name); - } - - for component in &self.components { - match component { - Component::Cell(_) => (), - Component::Module(module) => { - if path[0] == module.name { - return module.get_module_port_int(path[1..].to_vec(), name); - } - } - } - } - Err(ModuleError::MissingPort(name.to_string())) - } - - pub fn search_signal(&mut self, name: &str) -> Option { - for signal in &self.signals { - if signal.get_name() == name { - return Some(signal.get_value()); - } - } - - for component in &mut self.components { - match component { - Component::Cell(_) => (), - Component::Module(module) => match module.search_signal(name) { - Some(val) => return Some(val), - None => continue, - }, - } - } - None - } - - pub fn eval(&mut self) { - for component in &mut self.components { - match component { - Component::Cell(cell) => { - cell.eval(&mut self.signals); - } - Component::Module(module) => { - // Propagate input connections - for (external_idx, internal_idx) in &module.input_connections { - let bit = self.signals[*external_idx].get_value(); - module.signals[*internal_idx].set_value(bit); - } - module.eval(); - // Propagate output connections - for (external_idx, internal_idx) in &module.output_connections { - let bit = module.signals[*internal_idx].get_value(); - self.signals[*external_idx].set_value(bit); - } - } - } - } - } - - pub fn reset(&mut self) { - // Reset signals - self.signals.iter_mut().for_each(|signal| signal.reset()); - - // Reset components - self - .components - .iter_mut() - .for_each(|component| match component { - Component::Cell(cell) => cell.reset(), - Component::Module(module) => module.reset(), - }); - } - - pub fn set_port_shape(&mut self, name: &str, shape: &[usize; 2]) -> Result<(), ModuleError> { - match self.ports.get_mut(name) { - Some(port) => match port.set_shape(shape) { - Ok(()) => Ok(()), - Err(err) => Err(ModuleError::Port(name.to_string(), err)), - }, - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn get_port_shape(&self, name: &str) -> Result<[usize; 2], ModuleError> { - match self.ports.get(name) { - Some(port) => Ok(port.get_shape()), - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn get_port_direction(&self, name: &str) -> Result { - match self.ports.get(name) { - Some(port) => Ok(port.direction.clone()), - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn get_port_bits(&self, name: &str) -> Result { - match self.ports.get(name) { - Some(port) => Ok(port.get_bits(&self.signals)), - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn set_port_bits(&mut self, name: &str, vals: &BitVec) -> Result<(), ModuleError> { - match self.ports.get_mut(name) { - Some(port) => match port.set_bits(vals, &mut self.signals) { - Ok(()) => Ok(()), - Err(err) => Err(ModuleError::Port(name.to_string(), err)), - }, - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn get_port_int( - &self, - name: &str, - ) -> Result { - match self.ports.get(name) { - Some(port) => Ok(port.get_int(&self.signals)), - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn set_port_int( - &mut self, - name: &str, - val: T, - ) -> Result<(), ModuleError> { - match self.ports.get_mut(name) { - Some(port) => match port.set_int(val, &mut self.signals) { - Ok(()) => Ok(()), - Err(err) => Err(ModuleError::Port(name.to_string(), err)), - }, - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn get_port_int_vec( - &self, - name: &str, - ) -> Result, ModuleError> { - match self.ports.get(name) { - Some(port) => Ok(port.get_int_vec(&self.signals)), - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn set_port_int_vec( - &mut self, - name: &str, - vals: &[T], - ) -> Result<(), ModuleError> { - match self.ports.get_mut(name) { - Some(port) => match port.set_int_vec(vals, &mut self.signals) { - Ok(()) => Ok(()), - Err(err) => Err(ModuleError::Port(name.to_string(), err)), - }, - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn get_port_ndarray( - &self, - name: &str, - ) -> Result, ModuleError> { - match self.ports.get(name) { - Some(port) => Ok(port.get_ndarray(&self.signals)), - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn set_port_ndarray( - &mut self, - name: &str, - vals: ArrayView1, - ) -> Result<(), ModuleError> { - match self.ports.get(name) { - Some(port) => match port.set_ndarray(vals, &mut self.signals) { - Ok(()) => Ok(()), - Err(err) => Err(ModuleError::Port(name.to_string(), err)), - }, - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn get_port_string(&self, name: &str) -> Result { - match self.ports.get(name) { - Some(port) => Ok(port.get_string(&self.signals)), - None => Err(ModuleError::MissingPort(name.to_string())), - } - } - - pub fn get_cell_breakdown(&self) -> HashMap { - let mut breakdown = HashMap::::new(); - for component in &self.components { - match component { - Component::Cell(cell) => { - if !breakdown.contains_key(&cell.name) { - breakdown.insert(cell.name.clone(), 0); - } - - *breakdown.get_mut(&cell.name).unwrap() += 1; - } - Component::Module(module) => { - for (cell_name, count) in module.get_cell_breakdown() { - if !breakdown.contains_key(&cell_name) { - breakdown.insert(cell_name.clone(), 0); - } - *breakdown.get_mut(&cell_name).unwrap() += count; - } - } - } - } - breakdown - } - - pub fn search_module_cell_breakdown( - &self, - name: &str, - ) -> Result, ModuleError> { - if name == self.name { - Ok(self.get_cell_breakdown()) - } else { - for component in &self.components { - match component { - Component::Cell(_) => continue, - Component::Module(sub_module) => match sub_module.search_module_cell_breakdown(name) { - Ok(breakdown) => return Ok(breakdown), - Err(_) => continue, - }, - } - } - Err(ModuleError::MissingModule(name.to_string())) - } - } - - // TODO: Add tests for these - - pub fn get_total_toggle_count(&self) -> usize { - let mut total_toggles: usize = 0; - let input_connections: HashSet = self - .input_connections - .iter() - .map(|(_, internal_idx)| *internal_idx) - .collect(); - self.signals.iter().for_each(|signal| { - if !input_connections.contains(&signal.get_index()) { - total_toggles += signal.get_total_toggle_count(); - } - }); - self - .components - .iter() - .for_each(|component| match component { - Component::Cell(_) => (), - Component::Module(module) => total_toggles += module.get_total_toggle_count(), - }); - - total_toggles - } - - pub fn search_module_total_toggle_count(&self, name: &str) -> Result { - if name == self.name { - Ok(self.get_total_toggle_count()) - } else { - for component in &self.components { - match component { - Component::Cell(_) => continue, - Component::Module(sub_module) => { - match sub_module.search_module_total_toggle_count(name) { - Ok(count) => return Ok(count), - Err(_) => continue, - } - } - } - } - Err(ModuleError::MissingModule(name.to_string())) - } - } - - // need wrapper function to get input ports and not use connections - pub fn get_module_bit_flips(&self, name: &str) -> usize { - if self.name == name { - let mut total_toggles = 0; - - let input_connections: HashSet = self - .input_connections - .iter() - .map(|(_, internal_idx)| *internal_idx) - .collect(); - self.signals.iter().for_each(|signal| { - if !input_connections.contains(&signal.get_index()) { - total_toggles += signal.get_total_toggle_count(); - } - }); - - return total_toggles; - } else { - for component in &self.components { - match component { - Component::Module(module) if module.name == name => { - return module.get_module_bit_flips(name) - } - _ => continue, - } - } - } - 0 - } -} diff --git a/crates/arbolta/src/module/mod.rs b/crates/arbolta/src/module/mod.rs deleted file mode 100644 index af45b56..0000000 --- a/crates/arbolta/src/module/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -pub mod design; -pub mod hardware_module; -pub mod port; diff --git a/crates/arbolta/src/module/port.rs b/crates/arbolta/src/module/port.rs deleted file mode 100644 index 73787fc..0000000 --- a/crates/arbolta/src/module/port.rs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use crate::bit::{Bit, BitVec}; -use crate::signal::{AccessSignal, SignalIndexList, SignalList}; -use ndarray::{Array1, ArrayView1}; -use num_traits::PrimInt; -use serde::{Deserialize, Serialize}; -use std::fmt::Debug; -use thiserror::Error; - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub enum PortDirection { - Input, - Output, -} - -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] -pub struct Port { - pub signal_idx_list: SignalIndexList, - pub shape: [usize; 2], - pub direction: PortDirection, - pub signed: bool, -} - -#[derive(Debug, Error)] -pub enum PortError { - #[error("tried to set input port")] - Direction, - #[error("couldn't convert port to type")] - Conversion, - #[error("incompatible shapes: requested={requested:?}, actual={actual:?}")] - Shape { - requested: [usize; 2], - actual: [usize; 2], - }, -} - -impl Port { - pub fn set_shape(&mut self, shape: &[usize; 2]) -> Result<(), PortError> { - if shape[0] * shape[1] != self.signal_idx_list.len() { - return Err(PortError::Shape { - requested: *shape, - actual: self.shape, - }); - } - - (self.shape[0], self.shape[1]) = (shape[0], shape[1]); - - Ok(()) - } - - pub fn get_shape(&self) -> [usize; 2] { - self.shape - } - - pub fn get_bits(&self, signals: &SignalList) -> BitVec { - BitVec::from( - self - .signal_idx_list - .iter() - .map(|idx| signals[*idx].get_value()) - .collect::>(), - ) - } - - pub fn set_bits(&self, vals: &BitVec, signals: &mut SignalList) -> Result<(), PortError> { - if self.direction == PortDirection::Output { - return Err(PortError::Direction); - } - - let stop_idx = vals.bits.len(); - - for (i, val) in vals - .bits - .iter() - .enumerate() - .take(stop_idx.clamp(0, self.signal_idx_list.len())) - { - signals[self.signal_idx_list[i]].set_value(*val); - } - - Ok(()) - } - - pub fn get_int(&self, signals: &SignalList) -> T { - self.get_bits(signals).to_int() - } - - pub fn set_int( - &self, - val: T, - signals: &mut SignalList, - ) -> Result<(), PortError> { - if self.direction == PortDirection::Output { - return Err(PortError::Direction); - } - - let Ok(bits) = BitVec::from_int(val) else { - return Err(PortError::Direction); - }; - - self.set_bits(&bits, signals) - } - - pub fn get_int_vec(&self, signals: &SignalList) -> Vec { - let elem_size = self.shape[1]; - self.get_bits(signals).to_ints_sized(elem_size) - } - - pub fn set_int_vec( - &self, - vals: &[T], - signals: &mut SignalList, - ) -> Result<(), PortError> { - if vals.len() != self.shape[0] { - return Err(PortError::Shape { - requested: [vals.len(), std::mem::size_of::() * 8], - actual: self.shape, - }); - } - - let elem_size = self.shape[1]; - - match BitVec::from_ints_sized(vals, elem_size) { - Ok(bits) => self.set_bits(&bits, signals), - Err(_) => Err(PortError::Conversion), - } - } - - pub fn get_ndarray( - &self, - signals: &SignalList, - ) -> Array1 { - let elem_size = self.shape[1]; - self.get_bits(signals).to_int_ndarray_sized(elem_size) - } - - pub fn set_ndarray( - &self, - vals: ArrayView1, - signals: &mut SignalList, - ) -> Result<(), PortError> { - if vals.len() != self.shape[0] { - return Err(PortError::Shape { - requested: [vals.len(), std::mem::size_of::() * 8], - actual: self.shape, - }); - } - - let elem_size = self.shape[1]; - - match BitVec::from_int_ndarray_sized(vals, elem_size) { - Ok(bits) => self.set_bits(&bits, signals), - Err(_) => Err(PortError::Conversion), - } - } - - pub fn get_string(&self, signals: &SignalList) -> String { - self.get_bits(signals).to_string() - } -} diff --git a/crates/arbolta/src/netlist_wrapper.rs b/crates/arbolta/src/netlist_wrapper.rs new file mode 100644 index 0000000..ed5d32c --- /dev/null +++ b/crates/arbolta/src/netlist_wrapper.rs @@ -0,0 +1,337 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use crate::{ + cell::{Cell, CellMapping, create_cell}, + hardware_module::ModuleError, + port::{Port, PortDirection, parse_bit}, + yosys::{self, Netlist, RTLID, TopoOrder}, +}; +use indexmap::{IndexSet, indexmap}; +use petgraph::prelude::*; +use serde::{Deserialize, Serialize}; +use std::collections::{BTreeMap, HashMap, HashSet}; + +#[derive(Debug, Deserialize, Serialize, Default, Clone)] +pub struct NetlistWrapper { + pub top_module: String, + pub netlist: Netlist, + pub cells: Vec, // Should be in topological order + pub modules: HashSet>, + pub nets: HashMap>, + pub names_to_nets: HashMap>, +} + +impl NetlistWrapper { + pub fn new( + netlist: Netlist, + top_module: Option<&str>, + torder: TopoOrder, + hierarchy_separator: Option<&str>, + ) -> Result { + let mut netlist = netlist; + + let top_module = top_module + .or(find_top_module_name(&netlist)) + .ok_or(ModuleError::TopModule)? + .to_string(); + let module = netlist.modules.get_mut(&top_module).unwrap(); + + let torder_cells = IndexSet::<&str>::from_iter( + torder + .get(top_module.as_str()) + .ok_or(ModuleError::TopModule)? + .clone(), + ); + // Rearrange cells in topological order, put $scopeinfo at end + module.cells.sort_by_key(|cell_name, _| { + torder_cells + .get_index_of(cell_name.as_str()) + .unwrap_or(usize::MAX) + }); + + let (cells, cell_modules) = parse_cells(module, hierarchy_separator)?; + let nets = parse_nets(module, hierarchy_separator)?; + let names_to_nets = HashMap::from_iter(nets.iter().map(|(id, n)| (id.to_string(), n.clone()))); + + // Add modules only seen in nets (no synthesized cells) + let modules = HashSet::from_iter( + cell_modules + .into_iter() + .chain(nets.keys().map(|id| id.parents.clone())), + ); + + Ok(Self { + top_module, + netlist, + cells, + modules, + nets, + names_to_nets, + }) + } + + pub fn find_module_ports>( + &self, + parents: Option<&[S]>, + ) -> Result, ModuleError> { + let parents: Vec<&str> = match parents { + Some(p) => p.iter().map(|s| s.as_ref()).collect(), + None => vec![self.top_module.as_ref()], + }; + + // TODO: better errors + let module = self + .netlist + .modules + .get(&parents.join(".")) + .ok_or(ModuleError::MissingModule)?; + + let mut ports = HashMap::new(); + for (port_name, port_info) in &module.ports { + ports.insert(port_name.clone(), Port::try_from(port_info)?); + } + + Ok(ports) + } + + // Only looks in TOP module + pub fn find_cell(&self, id: &RTLID) -> Option<&yosys::Cell> { + let module = &self.netlist.modules[&self.top_module]; + // TODO: make this more efficient + module.cells.get(&id.to_string()) + } + + fn build_cell(&self, cell: &RTLID, mapping: Option<&CellMapping>) -> Result { + let synth_cell = self + .find_cell(cell) + .ok_or(ModuleError::MissingCell(cell.to_string()))?; + + let mut connections = BTreeMap::new(); + for (port_name, bits) in &synth_cell.connections { + let nets: Vec = bits.iter().map(parse_bit).collect::, _>>()?; + connections.insert(port_name.as_str(), nets.into_boxed_slice()); + } + + let mut parameters = BTreeMap::new(); + for (param_name, param) in &synth_cell.parameters { + // TODO: Error handling + if let Some(param) = param.to_number() { + parameters.insert(param_name.as_str(), param); + } else { + // TODO: Handle later + println!("Ignoring parameter `{param_name}={param:?}`"); + } + } + + Ok(create_cell( + &synth_cell.cell_type, + &connections, + ¶meters, + mapping, + )?) + } + + pub fn build_cells(&self, mapping: Option<&CellMapping>) -> Result, ModuleError> { + let cells = self + .cells + .iter() + .rev() + .map(|c| Self::build_cell(self, c, mapping)) + .collect::, _>>()?; + Ok(cells) + } + + // CLEAN + pub fn build_graph(&self) -> Result { + let mut graph = NetlistGraph::new(); + let mut cell_nodes = BTreeMap::<&RTLID, NodeIndex>::new(); + let mut bit_drivers = BTreeMap::>::new(); + let mut bit_users = BTreeMap::>::new(); + + let input_cell = RTLID::new(&[], &"$input"); + let output_cell = RTLID::new(&[], &"$output"); + let module = &self.netlist.modules[&self.top_module]; + for port_info in module.ports.values() { + if port_info.direction == yosys::PortDirection::Input { + let nets: Vec = port_info + .bits + .iter() + .map(parse_bit) + .collect::, _>>()?; + for n in nets { + bit_drivers.entry(n).or_default().insert(&input_cell); + } + } else if port_info.direction == yosys::PortDirection::Output { + let nets: Vec = port_info + .bits + .iter() + .map(parse_bit) + .collect::, _>>()?; + for n in nets { + bit_users.entry(n).or_default().insert(&output_cell); + } + } + } + cell_nodes.insert(&input_cell, graph.add_node(input_cell.clone())); + cell_nodes.insert(&output_cell, graph.add_node(output_cell.clone())); + + for cell_id in &self.cells { + let cell = self.find_cell(cell_id).unwrap(); + + for (port_name, bits) in &cell.connections { + if let Some(direction) = cell.port_directions.get(port_name) { + let direction = PortDirection::try_from(direction)?; + let nets: Vec = bits.iter().map(parse_bit).collect::, _>>()?; + + for n in nets { + match direction { + PortDirection::Input => { + bit_users.entry(n).or_default().insert(cell_id); + } + PortDirection::Output => { + bit_drivers.entry(n).or_default().insert(cell_id); + } + } + } + } + } + cell_nodes.insert(cell_id, graph.add_node(cell_id.clone())); + } + + for (net, user_cells) in &bit_users { + if let Some(drivers) = bit_drivers.get(net) { + for driver_cell in drivers { + let driver_node = &cell_nodes[driver_cell]; + + for user_cell in user_cells { + let user_node = &cell_nodes[user_cell]; + + graph.add_edge(*driver_node, *user_node, *net); + } + } + } + } + + Ok(graph) + } +} + +pub type NetlistGraph = DiGraph; + +/// Returns (cells, modules) +fn parse_cells( + module: &mut yosys::Module, + hierarchy_separator: Option<&str>, +) -> Result<(Vec, Vec>), ModuleError> { + let mut scope_cells = vec![]; + let mut primitive_cells = vec![]; + + // Separate cells into scope and primitive + module.cells.iter().for_each(|(cell_name, cell_info)| { + if cell_info.cell_type == "$scopeinfo" { + scope_cells.push((cell_name, cell_info)); + } else { + primitive_cells.push((cell_name, cell_info)); + } + }); + + let mut modules = vec![]; + for (scope_name, cell_info) in scope_cells { + if let Some(hdlname) = cell_info.attributes.get("hdlname") + && let Some(hdlname) = hdlname.to_string_if_string() + { + modules.push( + hdlname + .split(" ") + .map(|s| s.to_string()) + .collect::>(), + ); + } else { + modules.push(vec![scope_name.clone()]) + } + } + + let mut cells = vec![]; + let mut new_cells = indexmap! {}; + for (cell_name, cell_info) in primitive_cells { + // TODO: Check if cell is primitive? + let id = if let Some(scopename) = cell_info.attributes.get("scopename") + && let Some(scopename) = scopename.to_string_if_string() + { + RTLID::new(&[scopename], &cell_name.as_str()) + } else if let Some(split_name) = + hierarchy_separator.map(|s| cell_name.split(s).collect::>()) + && let Some((name, parents)) = split_name.split_last() + { + // Add new module + modules.push(parents.iter().map(|s| s.to_string()).collect()); + RTLID::new(parents, name) + } else { + RTLID::new(&[], cell_name) + }; + + new_cells.insert(id.to_string(), cell_info.clone()); + cells.push(id); + } + + module.cells = new_cells; + + Ok((cells, modules)) +} + +fn parse_nets( + module: &mut yosys::Module, + hierarchy_separator: Option<&str>, +) -> Result>, ModuleError> { + let mut all_nets = HashMap::new(); + + let mut new_nets = indexmap! {}; + for (net_name, net_info) in &module.netnames { + let id = if let Some(scopename) = net_info.attributes.get("scopename") + && let Some(scopename) = scopename.to_string_if_string() + { + RTLID::new(&[scopename], &net_name.as_str()) + } else if let Some(hdlname) = net_info.attributes.get("hdlname") + && let Some(hdlname) = hdlname.to_string_if_string() + { + let hdlname_split: Vec<&str> = hdlname.split(" ").collect(); + let (name, parents) = hdlname_split.split_last().unwrap(); + RTLID::new(parents, name) + } else if let Some(split_name) = + hierarchy_separator.map(|s| net_name.split(s).collect::>()) + && let Some((name, parents)) = split_name.split_last() + { + RTLID::new(parents, name) + } else { + RTLID::new(&[], net_name) + }; + + new_nets.insert(id.to_string(), net_info.clone()); + + let nets: Vec = net_info + .bits + .iter() + .map(parse_bit) + .collect::>()?; + + all_nets.insert(id, nets.into_boxed_slice()); + } + + module.netnames = new_nets; + + Ok(all_nets) +} + +fn find_top_module_name(netlist: &Netlist) -> Option<&str> { + for (module_name, module_info) in &netlist.modules { + if let Some(top_val) = module_info.attributes.get("top") + && let Some(top) = top_val.to_number() + && top == 1 + { + return Some(module_name); + } + } + + None +} diff --git a/crates/arbolta/src/port.rs b/crates/arbolta/src/port.rs new file mode 100644 index 0000000..fbec008 --- /dev/null +++ b/crates/arbolta/src/port.rs @@ -0,0 +1,100 @@ +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use crate::yosys; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; +use thiserror::Error; + +#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Deserialize, Serialize)] +pub enum PortDirection { + Input, + Output, +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +pub struct Port { + pub direction: PortDirection, + pub shape: [usize; 2], // TODO: Change this to option? +} + +/// Parse global net from `BitVal`. +/// Errors if bit direction is not supported. +pub fn parse_bit(bit: &yosys::BitVal) -> Result { + match bit { + yosys::BitVal::N(net) => Ok(*net), + yosys::BitVal::S(constant) => match constant { + yosys::SpecialBit::_0 => Ok(0), // Global 0 + yosys::SpecialBit::_1 => Ok(1), // Global 1 + yosys::SpecialBit::X => Err(PortError::Direction("X".to_string())), + yosys::SpecialBit::Z => Err(PortError::Direction("Z".to_string())), + }, + } +} + +#[derive(Debug, Error)] +pub enum PortError { + #[error("Direction `{0}` not supported")] + Direction(String), + #[error("couldn't convert port to type")] + Conversion, + #[error("incompatible shapes: requested={requested:?}, actual={actual:?}")] + Shape { + requested: [usize; 2], + actual: [usize; 2], + }, +} + +impl TryFrom<&yosys::PortDirection> for PortDirection { + type Error = PortError; + fn try_from(direction: &yosys::PortDirection) -> Result { + match direction { + yosys::PortDirection::InOut => Err(PortError::Direction("inout".to_string())), + yosys::PortDirection::Input => Ok(PortDirection::Input), + yosys::PortDirection::Output => Ok(PortDirection::Output), + } + } +} + +impl TryFrom<&yosys::Port> for Port { + type Error = PortError; + fn try_from(port: &yosys::Port) -> Result { + let direction = PortDirection::try_from(&port.direction)?; + let shape = [1, port.bits.len()]; + + Ok(Self { direction, shape }) + } +} + +impl Port { + // TODO: Remove and use try_from + // pub fn new(port: &yosys_json::Port) -> Result { + // let direction = PortDirection::try_from(&port.direction)?; + // let nets: Vec = port.bits.iter().map(parse_bit).collect::>()?; + // let shape = [1, nets.len()]; + + // Ok(Self { + // direction, + // nets: nets.into(), + // shape, + // }) + // } + + pub fn set_shape(&mut self, shape: &[usize; 2]) -> Result<(), PortError> { + if shape[0] * shape[1] != self.shape[0] * self.shape[1] { + Err(PortError::Shape { + requested: *shape, + actual: self.shape, + }) + } else { + (self.shape[0], self.shape[1]) = (shape[0], shape[1]); + + Ok(()) + } + } + + pub fn get_shape(&self) -> [usize; 2] { + self.shape + } +} diff --git a/crates/arbolta/src/signal.rs b/crates/arbolta/src/signal.rs index 170589f..1675ba1 100644 --- a/crates/arbolta/src/signal.rs +++ b/crates/arbolta/src/signal.rs @@ -1,178 +1,132 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding // SPDX-License-Identifier: MIT use crate::bit::Bit; use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -pub type SignalIndex = usize; -pub type SignalList = Vec; -pub type SignalIndexList = Vec; -pub type SignalIndexMap = BTreeMap; - -/// Connection between cells/modules. +/// Connection between cells/modules and related statistics. #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)] -pub struct Net { - /// Name of net - pub name: String, - /// Index in netlist connections (proxy to Yosys bit) - pub index: usize, - /// Value of net - pub value: Bit, +pub struct Signals { + // Total number of nets + pub size: usize, + /// Value of nets + pub nets: Box<[Bit]>, // TODO: Make this private + /// Signals have been modified + dirty: bool, + // Is net constant + constant: Box<[bool]>, /// Number of times net has transitioned from 0 -> 1 - pub toggle_count_rising: usize, + toggles_rising: Box<[u64]>, /// Number of times net has transitioned from 1 -> 0 - pub toggle_count_falling: usize, + toggles_falling: Box<[u64]>, } -/// Connection between cells/modules or constant. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] -pub enum Signal { - Constant(Bit), - Net(Net), -} +impl Signals { + pub fn new(size: usize) -> Self { + Self { + size, + dirty: false, + nets: vec![Bit::ZERO; size].into(), + constant: vec![false; size].into(), + toggles_rising: vec![0; size].into(), + toggles_falling: vec![0; size].into(), + } + } -impl Signal { - /// Create a new constant. - /// + /// Set value of net. Updates toggle statistics. /// # Arguments - /// * `value` - Constant `Bit` value. - pub fn new_constant(value: Bit) -> Self { - Self::Constant(value) + /// * `net` - Selected signal net. + /// * `val` - New `Bit` value to change `net` to. + #[inline] + pub fn set_net(&mut self, net: usize, val: Bit) { + // Constant or unchanged, do nothing + if self.constant[net] || self.nets[net] == val { + return; + } + + match val { + Bit::ONE => self.toggles_rising[net] += 1, + Bit::ZERO => self.toggles_falling[net] += 1, + } + + self.dirty = true; + self.nets[net] = val; } - /// Create a new net. - /// + /// Get value of net. /// # Arguments - /// * `index` - Net index. - pub fn new_net(index: usize) -> Self { - Self::Net(Net { - index, - ..Default::default() - }) + /// * `net` - Selected signal net. + #[inline] + pub fn get_net(&self, net: usize) -> Bit { + self.nets[net] } - /// Create a new net. + /// Make net constant. + /// Net cannot be updated until calling `unset_constant`. /// /// # Arguments - /// * `index` - Net index. - /// * `value` - Value to initialize net with. - pub fn new_net_from(index: usize, value: Bit) -> Self { - Self::Net(Net { - index, - value, - ..Default::default() - }) + /// * `net` - Selected signal net. + /// * `val` - Constant `Bit` value. + #[inline] + pub fn set_constant(&mut self, net: usize, val: Bit) { + self.constant[net] = true; + self.nets[net] = val; } - /// Create a new list of `Signal`s. - /// List initialized with zero `Constant`s. + /// Make net modifiable. /// /// # Arguments - /// * `size` - Size of list. - pub fn new_list(size: usize) -> SignalList { - let mut signal_list = SignalList::with_capacity(size); - for _ in 0..size { - signal_list.push(Self::new_constant(Bit::Zero)); - } - signal_list + /// * `net` - Selected signal net. + #[inline] + pub fn unset_constant(&mut self, net: usize) { + self.constant[net] = false; } -} - -pub trait AccessSignal { - fn reset(&mut self); - fn set_name(&mut self, name: String); - fn get_name(&self) -> &str; - fn get_index(&self) -> usize; - fn get_value(&self) -> Bit; - fn set_value(&mut self, val: Bit); - fn get_total_toggle_count(&self) -> usize; - fn get_toggle_count_rising(&self) -> usize; - fn get_toggle_count_falling(&self) -> usize; -} -impl AccessSignal for Signal { - /// Reset signal value to zero. - /// Clear all signal statistics. - fn reset(&mut self) { - match self { - Signal::Constant(_) => (), // Do nothing - Signal::Net(net) => { - net.toggle_count_rising = 0; - net.toggle_count_falling = 0; - net.value = Bit::Zero; - } - } + #[inline] + pub fn is_dirty(&self) -> bool { + self.dirty } - /// Set name of signal. - fn set_name(&mut self, name: String) { - match self { - Signal::Constant(_) => (), // Do nothing - Signal::Net(net) => net.name = name, - } + #[inline] + pub fn clear_dirty(&mut self) { + self.dirty = false } - /// Get name of signal. - fn get_name(&self) -> &str { - match self { - Signal::Constant(_) => "const", // Do nothing - Signal::Net(net) => &net.name, - } + /// Reset all nets to `Bit::ZERO` and clear statistics. + pub fn reset(&mut self) { + self.dirty = false; + self.nets.iter_mut().for_each(|n| *n = Bit::ZERO); + self.constant.iter_mut().for_each(|c| *c = false); + self.toggles_rising.iter_mut().for_each(|t| *t = 0); + self.toggles_falling.iter_mut().for_each(|t| *t = 0); } - /// Get netlist index of signal. - fn get_index(&self) -> usize { - match self { - Signal::Constant(_) => 0, // TODO: Improve constant handling - Signal::Net(net) => net.index, - } - } - - /// Get value of signal. - fn get_value(&self) -> Bit { - match self { - Signal::Constant(bit) => *bit, - Signal::Net(net) => net.value, - } - } - - /// Set value of signal. Updates toggle statistics. - fn set_value(&mut self, val: Bit) { - match self { - Signal::Constant(_) => (), // Do nothing - Signal::Net(net) => { - match &[net.value, val] { - [Bit::Zero, Bit::One] => net.toggle_count_rising += 1, - [Bit::One, Bit::Zero] => net.toggle_count_falling += 1, - [Bit::Zero, Bit::Zero] | [Bit::One, Bit::One] => return, - } - net.value = val; - } - } - } - - /// Get total signal toggle count (rising + falling). - fn get_total_toggle_count(&self) -> usize { - match self { - Signal::Constant(_) => 0, - Signal::Net(net) => net.toggle_count_falling + net.toggle_count_rising, - } + /// Total number times `net` has been toggled since last reset. + /// Includes both rising (0->1) and falling (1->0). + /// + /// # Arguments + /// * `net` - Selected signal net. + #[inline] + pub fn get_toggles_total(&self, net: usize) -> u64 { + self.toggles_falling[net] + self.toggles_rising[net] } - /// Get total rising toggle count of signal. - fn get_toggle_count_rising(&self) -> usize { - match self { - Signal::Constant(_) => 0, - Signal::Net(net) => net.toggle_count_rising, - } + /// Total number times `net` has been toggled from 0 -> 1. + /// + /// # Arguments + /// * `net` - Selected signal net. + #[inline] + pub fn get_toggles_rising(&self, net: usize) -> u64 { + self.toggles_rising[net] } - /// Get total falling toggle count of signal. - fn get_toggle_count_falling(&self) -> usize { - match self { - Signal::Constant(_) => 0, - Signal::Net(net) => net.toggle_count_falling, - } + /// Total number times `net` has been toggled from 1 -> 0. + /// + /// # Arguments + /// * `net` - Selected signal net. + #[inline] + pub fn get_toggles_falling(&self, net: usize) -> u64 { + self.toggles_falling[net] } } diff --git a/crates/arbolta/src/synth/mod.rs b/crates/arbolta/src/synth/mod.rs deleted file mode 100644 index 9ebf465..0000000 --- a/crates/arbolta/src/synth/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -pub mod netlist; -pub mod yosys; diff --git a/crates/arbolta/src/synth/netlist.rs b/crates/arbolta/src/synth/netlist.rs deleted file mode 100644 index f6a6b72..0000000 --- a/crates/arbolta/src/synth/netlist.rs +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use crate::bit::Bit; -use crate::cell::{Cell, CellLibrary}; -use crate::module::hardware_module::{Component, ComponentIndexMap, HardwareModule, PortMap}; -use crate::module::port::{Port, PortDirection}; -use crate::signal::{AccessSignal, Signal, SignalIndexMap, SignalList}; -use std::collections::BTreeMap; -use std::io; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum SynthError { - #[error("Module `{0}` does not exist")] - MissingModule(String), - #[error("Error opening netlist: {0}")] - Netlist(String), - #[error("{0}")] - IoError(#[from] io::Error), -} - -#[derive(Debug)] -pub enum SynthBit { - Constant(Bit), - NetIndex(usize), -} - -#[derive(Debug)] -pub struct SynthPort { - pub direction: PortDirection, - pub bits: Vec, // context of local module - pub signed: bool, -} - -#[derive(Debug)] -pub struct SynthCell { - pub cell_type: String, - pub connections: BTreeMap>, -} - -#[derive(Debug)] -pub struct SynthModule { - // Preserve topological order of cells - pub ports: BTreeMap, - pub cells: BTreeMap, - pub nets: BTreeMap>, // context of local module -} - -impl SynthModule { - pub fn max_net_idx(&self) -> usize { - self - .nets - .values() - .map(|bits| { - bits - .iter() - .map(|x| match x { - SynthBit::Constant(_) => 0, - SynthBit::NetIndex(idx) => *idx, - }) - .max() - .unwrap() - }) - .max() - .unwrap() - } -} - -impl From<&SynthBit> for Signal { - fn from(value: &SynthBit) -> Self { - match value { - SynthBit::Constant(x) => Signal::new_constant(*x), - SynthBit::NetIndex(x) => Signal::new_net(*x), - } - } -} - -impl From for Signal { - fn from(value: SynthBit) -> Self { - Self::from(&value) - } -} - -impl From<&SynthPort> for Port { - fn from(value: &SynthPort) -> Self { - let signal_idx_list: Vec = value - .bits - .iter() - .map(|x| match x { - SynthBit::Constant(bit) => match bit { - Bit::Zero => 0, - Bit::One => 1, - }, - SynthBit::NetIndex(idx) => *idx, - }) - .collect(); - - let shape = [1, signal_idx_list.len()]; - - Self { - signal_idx_list, - shape, - direction: value.direction.clone(), - signed: value.signed, - } - } -} - -impl From for Port { - fn from(value: SynthPort) -> Self { - Self::from(&value) - } -} - -#[derive(Debug)] -pub struct Netlist { - pub modules: BTreeMap, -} - -impl Netlist { - pub fn generate_module( - &self, - name: &str, - cell_library: &CellLibrary, - ) -> Result { - let top_module: &SynthModule = match self.modules.get(name) { - Some(x) => x, - None => return Err(SynthError::MissingModule(name.to_string())), - }; - - let ports: PortMap = top_module - .ports - .iter() - .map(|(port_name, port_synth)| (port_name.clone(), Port::from(port_synth))) - .collect(); - - let mut signals: SignalList = (0..(top_module.max_net_idx() + 1)) - .map(|_| Signal::new_constant(Bit::Zero)) - .collect(); - // Bits 0 and 1 are unused by Yosys so we keep them as constant 0 and 1 respectively - signals[1] = Signal::new_constant(Bit::One); - - let mut signal_map = SignalIndexMap::new(); - for (net_name, bits) in &top_module.nets { - for (i, bit) in bits.iter().enumerate() { - let signal_name = if bits.len() > 1 { - format!("{net_name}[{i}]") - } else { - net_name.clone() - }; - - match bit { - SynthBit::Constant(_) => (), // Do nothing - SynthBit::NetIndex(idx) => { - let mut signal = Signal::new_net(*idx); - signal_map.insert(signal_name.clone(), *idx); - signal.set_name(signal_name); - signals[*idx] = signal; - } - } - } - } - - let mut components: Vec = vec![]; - let mut component_map = ComponentIndexMap::new(); - - for (instance_name, synth_cell) in &top_module.cells { - let new_component = match cell_library.cells.get(&synth_cell.cell_type) { - Some(cell_info) => { - let mut cell = Cell::from(cell_info); - // flatten this for now, should only be 1 bit - for (i, bits) in synth_cell.connections.values().enumerate() { - let idx = match &bits[0] { - SynthBit::Constant(bit) => match bit { - Bit::Zero => 0, - Bit::One => 1, - }, - SynthBit::NetIndex(idx) => *idx, - }; - cell.input_connections[i] = idx; - } - // this sets last input as output but, fix later - cell.output_connection = cell.input_connections[cell.num_inputs]; - Component::Cell(cell) - } - None => { - let mut submodule = self.generate_module(&synth_cell.cell_type, cell_library)?; - for (port_name, bits) in &synth_cell.connections { - let port = submodule.ports.get(port_name).unwrap(); - for (i, bit) in bits.iter().enumerate() { - let idx = match bit { - SynthBit::Constant(bit) => match bit { - Bit::Zero => 0, - Bit::One => 1, - }, - SynthBit::NetIndex(idx) => *idx, - }; - - match port.direction { - PortDirection::Input => submodule - .input_connections - .push((idx, port.signal_idx_list[i])), - PortDirection::Output => submodule - .output_connections - .push((idx, port.signal_idx_list[i])), - } - } - } - Component::Module(submodule) - } - }; - component_map.insert(instance_name.clone(), components.len()); - components.push(new_component); - } - - Ok(HardwareModule { - name: name.to_string(), - ports, - signals, - signal_map, - components, - component_map, - input_connections: vec![], - output_connections: vec![], - }) - } -} diff --git a/crates/arbolta/src/synth/yosys.rs b/crates/arbolta/src/synth/yosys.rs deleted file mode 100644 index 5335fbf..0000000 --- a/crates/arbolta/src/synth/yosys.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use super::netlist::{Netlist, SynthBit, SynthCell, SynthError, SynthModule, SynthPort}; -use crate::bit::Bit; -use crate::module::port::PortDirection; -use std::collections::BTreeMap; - -impl From for PortDirection { - fn from(value: yosys_netlist_json::PortDirection) -> Self { - match value { - yosys_netlist_json::PortDirection::InOut => todo!("Inout not supported"), - yosys_netlist_json::PortDirection::Input => Self::Input, - yosys_netlist_json::PortDirection::Output => Self::Output, - } - } -} - -impl From for SynthBit { - fn from(value: yosys_netlist_json::BitVal) -> Self { - match value { - yosys_netlist_json::BitVal::N(idx) => Self::NetIndex(idx), - yosys_netlist_json::BitVal::S(constant) => Self::Constant(match constant { - yosys_netlist_json::SpecialBit::_0 => Bit::Zero, - yosys_netlist_json::SpecialBit::_1 => Bit::One, - yosys_netlist_json::SpecialBit::X => todo!("X not supported"), - yosys_netlist_json::SpecialBit::Z => todo!("Z not supported"), - }), - } - } -} - -impl From for SynthPort { - fn from(value: yosys_netlist_json::Port) -> Self { - Self { - direction: PortDirection::from(value.direction), - bits: value.bits.iter().map(|x| SynthBit::from(*x)).collect(), - signed: value.signed > 0, - } - } -} - -impl From for SynthCell { - fn from(value: yosys_netlist_json::Cell) -> Self { - let mut connections: BTreeMap> = BTreeMap::new(); - for (key, vals) in value.connections { - let bits: Vec = vals.iter().map(|x| SynthBit::from(*x)).collect(); - connections.insert(key, bits); - } - - Self { - cell_type: value.cell_type, - connections, - } - } -} - -impl From for SynthModule { - fn from(value: yosys_netlist_json::Module) -> Self { - let ports: BTreeMap = value - .ports - .into_iter() - .map(|(key, val)| (key.clone(), SynthPort::from(val))) - .collect(); - - let cells: BTreeMap = value - .cells - .into_iter() - .map(|(key, val)| (key.clone(), SynthCell::from(val))) - .collect(); - - let nets: BTreeMap> = value - .netnames - .into_iter() - .map(|(key, vals)| { - ( - key.clone(), - vals.bits.iter().map(|x| SynthBit::from(*x)).collect(), - ) - }) - .collect(); - - Self { ports, cells, nets } - } -} - -impl From for Netlist { - fn from(value: yosys_netlist_json::Netlist) -> Self { - let mut modules: BTreeMap = BTreeMap::new(); - for (key, val) in value.modules { - modules.insert(key, SynthModule::from(val)); - } - - Self { modules } - } -} - -impl Netlist { - pub fn from_yosys(json_path: &str) -> Result { - let raw_json = std::fs::read(json_path)?; - let Ok(raw_netlist) = yosys_netlist_json::Netlist::from_slice(&raw_json) else { - return Err(SynthError::Netlist(json_path.to_string())); - }; - - Ok(Netlist::from(raw_netlist)) - } - - pub fn from_yosys_raw(raw_json: &[u8]) -> Result { - let Ok(raw_netlist) = yosys_netlist_json::Netlist::from_slice(raw_json) else { - return Err(SynthError::Netlist("raw_json".to_string())); - }; - - Ok(Netlist::from(raw_netlist)) - } -} diff --git a/crates/arbolta/src/yosys.rs b/crates/arbolta/src/yosys.rs new file mode 100644 index 0000000..83d822c --- /dev/null +++ b/crates/arbolta/src/yosys.rs @@ -0,0 +1,85 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +// Re-export +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, fmt}; + +fn remove_whitespace>(s: &S) -> String { + s.as_ref().chars().filter(|c| !c.is_whitespace()).collect() +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Deserialize, Serialize, PartialOrd, Ord)] +pub struct RTLID { + pub parents: Vec, + pub name: String, +} + +impl RTLID { + pub fn new>(parents: &[S], name: &S) -> Self { + let mut name_clean = remove_whitespace(name); + let parents_clean: Vec = parents.iter().map(|p| remove_whitespace(p)).collect(); + + if !parents_clean.is_empty() { + let name_stripped = name_clean.strip_prefix("$flatten\\").unwrap_or(&name_clean); + let parents_prefix = format!("{}.", parents_clean.join(".")); + + if let Some(actual_name) = name_stripped.strip_prefix(&parents_prefix) { + name_clean = actual_name.to_string(); + } else { + name_clean = name_stripped.to_string(); + } + } + + Self { + parents: parents_clean, + name: name_clean, + } + } +} + +impl fmt::Display for RTLID { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.parents.is_empty() { + write!(f, "{}", self.name) + } else { + write!(f, "{}.{}", self.parents.join("."), self.name) + } + } +} + +pub type TopoOrder<'a> = HashMap<&'a str, Vec<&'a str>>; + +pub fn parse_torder<'a>(raw: &'a str) -> TopoOrder<'a> { + let mut torder = TopoOrder::new(); + let mut current_module: Option<&'a str> = None; + + for line in raw.lines() { + let line = line.trim(); + + // Start new module + if let Some(module_name) = line.strip_prefix("module ") { + let module_name = if let Some((_cell_type, module_name)) = module_name.split_once("$") { + module_name + } else { + module_name + }; + + current_module = Some(module_name); + torder.insert(module_name, vec![]); + } else if let Some(module_path) = current_module + && let Some(cell_name) = line.strip_prefix("cell ") + { + torder.entry(module_path).or_default().push(cell_name); + } + } + + torder +} + +// Re-export +pub use yosys_netlist_json::{ + AttributeVal, BitVal, Cell, Module, Netlist, Netname, Port, PortDirection, SpecialBit, +}; + +// TODO: Maybe re-add Yosys bindings... diff --git a/crates/arbolta/tests/deps/simcells_wrappers.json b/crates/arbolta/tests/deps/simcells_wrappers.json new file mode 100644 index 0000000..381c74c --- /dev/null +++ b/crates/arbolta/tests/deps/simcells_wrappers.json @@ -0,0 +1 @@ +{"creator": "Yosys 0.56+186 (git sha1 83d953e95, clang++ 18.1.8 -fPIC -O3)", "modules": {"$_ALDFFE_NNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1420.1-1429.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_ALDFFE_NNN_": {"type": "$_ALDFFE_NNN_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "E": [6], "Q": [7]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1421.16-1421.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1421.10-1421.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1421.7-1421.8"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1421.20-1421.21"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1421.13-1421.14"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1422.12-1422.13"}}}}, "$_ALDFFE_NNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1445.1-1454.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_ALDFFE_NNP_": {"type": "$_ALDFFE_NNP_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "E": [6], "Q": [7]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1446.16-1446.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1446.10-1446.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1446.7-1446.8"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1446.20-1446.21"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1446.13-1446.14"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1447.12-1447.13"}}}}, "$_ALDFFE_NPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1470.1-1479.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_ALDFFE_NPN_": {"type": "$_ALDFFE_NPN_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "E": [6], "Q": [7]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1471.16-1471.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1471.10-1471.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1471.7-1471.8"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1471.20-1471.21"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1471.13-1471.14"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1472.12-1472.13"}}}}, "$_ALDFFE_NPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1495.1-1504.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_ALDFFE_NPP_": {"type": "$_ALDFFE_NPP_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "E": [6], "Q": [7]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1496.16-1496.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1496.10-1496.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1496.7-1496.8"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1496.20-1496.21"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1496.13-1496.14"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1497.12-1497.13"}}}}, "$_ALDFFE_PNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1520.1-1529.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_ALDFFE_PNN_": {"type": "$_ALDFFE_PNN_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "E": [6], "Q": [7]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1521.16-1521.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1521.10-1521.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1521.7-1521.8"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1521.20-1521.21"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1521.13-1521.14"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1522.12-1522.13"}}}}, "$_ALDFFE_PNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1545.1-1554.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_ALDFFE_PNP_": {"type": "$_ALDFFE_PNP_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "E": [6], "Q": [7]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1546.16-1546.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1546.10-1546.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1546.7-1546.8"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1546.20-1546.21"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1546.13-1546.14"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1547.12-1547.13"}}}}, "$_ALDFFE_PPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1570.1-1579.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_ALDFFE_PPN_": {"type": "$_ALDFFE_PPN_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "E": [6], "Q": [7]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1571.16-1571.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1571.10-1571.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1571.7-1571.8"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1571.20-1571.21"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1571.13-1571.14"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1572.12-1572.13"}}}}, "$_ALDFFE_PPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1595.1-1604.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_ALDFFE_PPP_": {"type": "$_ALDFFE_PPP_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "E": [6], "Q": [7]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1596.16-1596.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1596.10-1596.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1596.7-1596.8"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1596.20-1596.21"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1596.13-1596.14"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1597.12-1597.13"}}}}, "$_ALDFF_NN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1323.1-1332.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_ALDFF_NN_": {"type": "$_ALDFF_NN_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "Q": [6]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1324.16-1324.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1324.10-1324.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1324.7-1324.8"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1324.13-1324.14"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1325.12-1325.13"}}}}, "$_ALDFF_NP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1347.1-1356.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_ALDFF_NP_": {"type": "$_ALDFF_NP_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "Q": [6]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1348.16-1348.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1348.10-1348.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1348.7-1348.8"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1348.13-1348.14"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1349.12-1349.13"}}}}, "$_ALDFF_PN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1371.1-1380.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_ALDFF_PN_": {"type": "$_ALDFF_PN_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "Q": [6]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1372.16-1372.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1372.10-1372.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1372.7-1372.8"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1372.13-1372.14"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1373.12-1373.13"}}}}, "$_ALDFF_PP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1395.1-1404.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "L": {"direction": "input", "bits": [4]}, "AD": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_ALDFF_PP_": {"type": "$_ALDFF_PP_", "port_directions": {"D": "input", "C": "input", "L": "input", "AD": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "L": [4], "AD": [5], "Q": [6]}}}, "netnames": {"AD": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1396.16-1396.18"}}, "C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1396.10-1396.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1396.7-1396.8"}}, "L": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1396.13-1396.14"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1397.12-1397.13"}}}}, "$_ANDNOT__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:198.1-202.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "Y": {"direction": "output", "bits": [4]}}, "cells": {"$_ANDNOT_": {"type": "$_ANDNOT_", "port_directions": {"A": "input", "B": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "Y": [4]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:199.7-199.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:199.10-199.11"}}, "Y": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:200.8-200.9"}}}}, "$_AND__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:78.1-82.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "Y": {"direction": "output", "bits": [4]}}, "cells": {"$_AND_": {"type": "$_AND_", "port_directions": {"A": "input", "B": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "Y": [4]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:79.7-79.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:79.10-79.11"}}, "Y": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:80.8-80.9"}}}}, "$_AOI3__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:367.1-371.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "C": {"direction": "input", "bits": [4]}, "Y": {"direction": "output", "bits": [5]}}, "cells": {"$_AOI3_": {"type": "$_AOI3_", "port_directions": {"A": "input", "B": "input", "C": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "C": [4], "Y": [5]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:368.7-368.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:368.10-368.11"}}, "C": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:368.13-368.14"}}, "Y": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:369.8-369.9"}}}}, "$_AOI4__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:423.1-427.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "C": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Y": {"direction": "output", "bits": [6]}}, "cells": {"$_AOI4_": {"type": "$_AOI4_", "port_directions": {"A": "input", "B": "input", "C": "input", "D": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "C": [4], "D": [5], "Y": [6]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:424.7-424.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:424.10-424.11"}}, "C": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:424.13-424.14"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:424.16-424.17"}}, "Y": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:425.8-425.9"}}}}, "$_BUF__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:40.1-44.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "Y": {"direction": "output", "bits": [3]}}, "cells": {"$_BUF_": {"type": "$_BUF_", "port_directions": {"A": "input", "Y": "output"}, "connections": {"A": [2], "Y": [3]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:41.7-41.8"}}, "Y": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:42.8-42.9"}}}}, "$_DFFE_NN0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:924.1-933.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_NN0N_": {"type": "$_DFFE_NN0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:925.10-925.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:925.7-925.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:925.16-925.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:926.12-926.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:925.13-925.14"}}}}, "$_DFFE_NN0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:949.1-958.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_NN0P_": {"type": "$_DFFE_NN0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:950.10-950.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:950.7-950.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:950.16-950.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:951.12-951.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:950.13-950.14"}}}}, "$_DFFE_NN1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:974.1-983.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_NN1N_": {"type": "$_DFFE_NN1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:975.10-975.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:975.7-975.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:975.16-975.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:976.12-976.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:975.13-975.14"}}}}, "$_DFFE_NN1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:999.1-1008.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_NN1P_": {"type": "$_DFFE_NN1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1000.10-1000.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1000.7-1000.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1000.16-1000.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1001.12-1001.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1000.13-1000.14"}}}}, "$_DFFE_NN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:650.1-656.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "E": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFFE_NN_": {"type": "$_DFFE_NN_", "port_directions": {"D": "input", "C": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "E": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:651.10-651.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:651.7-651.8"}}, "E": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:651.13-651.14"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:652.12-652.13"}}}}, "$_DFFE_NP0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1024.1-1033.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_NP0N_": {"type": "$_DFFE_NP0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1025.10-1025.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1025.7-1025.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1025.16-1025.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1026.12-1026.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1025.13-1025.14"}}}}, "$_DFFE_NP0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1049.1-1058.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_NP0P_": {"type": "$_DFFE_NP0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1050.10-1050.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1050.7-1050.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1050.16-1050.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1051.12-1051.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1050.13-1050.14"}}}}, "$_DFFE_NP1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1074.1-1083.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_NP1N_": {"type": "$_DFFE_NP1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1075.10-1075.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1075.7-1075.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1075.16-1075.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1076.12-1076.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1075.13-1075.14"}}}}, "$_DFFE_NP1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1099.1-1108.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_NP1P_": {"type": "$_DFFE_NP1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1100.10-1100.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1100.7-1100.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1100.16-1100.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1101.12-1101.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1100.13-1100.14"}}}}, "$_DFFE_NP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:670.1-676.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "E": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFFE_NP_": {"type": "$_DFFE_NP_", "port_directions": {"D": "input", "C": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "E": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:671.10-671.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:671.7-671.8"}}, "E": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:671.13-671.14"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:672.12-672.13"}}}}, "$_DFFE_PN0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1124.1-1133.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_PN0N_": {"type": "$_DFFE_PN0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1125.10-1125.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1125.7-1125.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1125.16-1125.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1126.12-1126.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1125.13-1125.14"}}}}, "$_DFFE_PN0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1149.1-1158.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_PN0P_": {"type": "$_DFFE_PN0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1150.10-1150.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1150.7-1150.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1150.16-1150.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1151.12-1151.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1150.13-1150.14"}}}}, "$_DFFE_PN1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1174.1-1183.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_PN1N_": {"type": "$_DFFE_PN1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1175.10-1175.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1175.7-1175.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1175.16-1175.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1176.12-1176.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1175.13-1175.14"}}}}, "$_DFFE_PN1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1199.1-1208.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_PN1P_": {"type": "$_DFFE_PN1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1200.10-1200.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1200.7-1200.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1200.16-1200.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1201.12-1201.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1200.13-1200.14"}}}}, "$_DFFE_PN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:690.1-696.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "E": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFFE_PN_": {"type": "$_DFFE_PN_", "port_directions": {"D": "input", "C": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "E": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:691.10-691.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:691.7-691.8"}}, "E": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:691.13-691.14"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:692.12-692.13"}}}}, "$_DFFE_PP0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1224.1-1233.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_PP0N_": {"type": "$_DFFE_PP0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1225.10-1225.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1225.7-1225.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1225.16-1225.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1226.12-1226.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1225.13-1225.14"}}}}, "$_DFFE_PP0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1249.1-1258.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_PP0P_": {"type": "$_DFFE_PP0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1250.10-1250.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1250.7-1250.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1250.16-1250.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1251.12-1251.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1250.13-1250.14"}}}}, "$_DFFE_PP1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1274.1-1283.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_PP1N_": {"type": "$_DFFE_PP1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1275.10-1275.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1275.7-1275.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1275.16-1275.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1276.12-1276.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1275.13-1275.14"}}}}, "$_DFFE_PP1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1299.1-1308.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFE_PP1P_": {"type": "$_DFFE_PP1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1300.10-1300.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1300.7-1300.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1300.16-1300.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1301.12-1301.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1300.13-1300.14"}}}}, "$_DFFE_PP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:710.1-716.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "E": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFFE_PP_": {"type": "$_DFFE_PP_", "port_directions": {"D": "input", "C": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "E": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:711.10-711.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:711.7-711.8"}}, "E": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:711.13-711.14"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:712.12-712.13"}}}}, "$_DFFSRE_NNNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1845.1-1856.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_NNNN_": {"type": "$_DFFSRE_NNNN_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1846.7-1846.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1846.19-1846.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1846.16-1846.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1847.12-1847.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1846.13-1846.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1846.10-1846.11"}}}}, "$_DFFSRE_NNNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1873.1-1884.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_NNNP_": {"type": "$_DFFSRE_NNNP_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1874.7-1874.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1874.19-1874.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1874.16-1874.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1875.12-1875.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1874.13-1874.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1874.10-1874.11"}}}}, "$_DFFSRE_NNPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1901.1-1912.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_NNPN_": {"type": "$_DFFSRE_NNPN_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1902.7-1902.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1902.19-1902.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1902.16-1902.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1903.12-1903.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1902.13-1902.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1902.10-1902.11"}}}}, "$_DFFSRE_NNPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1929.1-1940.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_NNPP_": {"type": "$_DFFSRE_NNPP_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1930.7-1930.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1930.19-1930.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1930.16-1930.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1931.12-1931.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1930.13-1930.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1930.10-1930.11"}}}}, "$_DFFSRE_NPNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1957.1-1968.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_NPNN_": {"type": "$_DFFSRE_NPNN_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1958.7-1958.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1958.19-1958.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1958.16-1958.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1959.12-1959.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1958.13-1958.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1958.10-1958.11"}}}}, "$_DFFSRE_NPNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1985.1-1996.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_NPNP_": {"type": "$_DFFSRE_NPNP_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1986.7-1986.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1986.19-1986.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1986.16-1986.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1987.12-1987.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1986.13-1986.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1986.10-1986.11"}}}}, "$_DFFSRE_NPPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2013.1-2024.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_NPPN_": {"type": "$_DFFSRE_NPPN_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2014.7-2014.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2014.19-2014.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2014.16-2014.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2015.12-2015.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2014.13-2014.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2014.10-2014.11"}}}}, "$_DFFSRE_NPPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2041.1-2052.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_NPPP_": {"type": "$_DFFSRE_NPPP_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2042.7-2042.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2042.19-2042.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2042.16-2042.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2043.12-2043.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2042.13-2042.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2042.10-2042.11"}}}}, "$_DFFSRE_PNNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2069.1-2080.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_PNNN_": {"type": "$_DFFSRE_PNNN_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2070.7-2070.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2070.19-2070.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2070.16-2070.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2071.12-2071.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2070.13-2070.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2070.10-2070.11"}}}}, "$_DFFSRE_PNNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2097.1-2108.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_PNNP_": {"type": "$_DFFSRE_PNNP_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2098.7-2098.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2098.19-2098.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2098.16-2098.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2099.12-2099.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2098.13-2098.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2098.10-2098.11"}}}}, "$_DFFSRE_PNPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2125.1-2136.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_PNPN_": {"type": "$_DFFSRE_PNPN_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2126.7-2126.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2126.19-2126.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2126.16-2126.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2127.12-2127.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2126.13-2126.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2126.10-2126.11"}}}}, "$_DFFSRE_PNPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2153.1-2164.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_PNPP_": {"type": "$_DFFSRE_PNPP_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2154.7-2154.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2154.19-2154.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2154.16-2154.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2155.12-2155.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2154.13-2154.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2154.10-2154.11"}}}}, "$_DFFSRE_PPNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2181.1-2192.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_PPNN_": {"type": "$_DFFSRE_PPNN_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2182.7-2182.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2182.19-2182.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2182.16-2182.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2183.12-2183.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2182.13-2182.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2182.10-2182.11"}}}}, "$_DFFSRE_PPNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2209.1-2220.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_PPNP_": {"type": "$_DFFSRE_PPNP_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2210.7-2210.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2210.19-2210.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2210.16-2210.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2211.12-2211.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2210.13-2210.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2210.10-2210.11"}}}}, "$_DFFSRE_PPPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2237.1-2248.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_PPPN_": {"type": "$_DFFSRE_PPPN_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2238.7-2238.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2238.19-2238.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2238.16-2238.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2239.12-2239.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2238.13-2238.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2238.10-2238.11"}}}}, "$_DFFSRE_PPPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2265.1-2276.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "D": {"direction": "input", "bits": [6]}, "Q": {"direction": "output", "bits": [7]}}, "cells": {"$_DFFSRE_PPPP_": {"type": "$_DFFSRE_PPPP_", "port_directions": {"C": "input", "S": "input", "R": "input", "E": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "E": [5], "D": [6], "Q": [7]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2266.7-2266.8"}}, "D": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2266.19-2266.20"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2266.16-2266.17"}}, "Q": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2267.12-2267.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2266.13-2266.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2266.10-2266.11"}}}}, "$_DFFSR_NNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1621.1-1632.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFSR_NNN_": {"type": "$_DFFSR_NNN_", "port_directions": {"C": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1622.7-1622.8"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1622.16-1622.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1623.12-1623.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1622.13-1622.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1622.10-1622.11"}}}}, "$_DFFSR_NNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1649.1-1660.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFSR_NNP_": {"type": "$_DFFSR_NNP_", "port_directions": {"C": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1650.7-1650.8"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1650.16-1650.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1651.12-1651.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1650.13-1650.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1650.10-1650.11"}}}}, "$_DFFSR_NPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1677.1-1688.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFSR_NPN_": {"type": "$_DFFSR_NPN_", "port_directions": {"C": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1678.7-1678.8"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1678.16-1678.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1679.12-1679.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1678.13-1678.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1678.10-1678.11"}}}}, "$_DFFSR_NPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1705.1-1716.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFSR_NPP_": {"type": "$_DFFSR_NPP_", "port_directions": {"C": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1706.7-1706.8"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1706.16-1706.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1707.12-1707.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1706.13-1706.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1706.10-1706.11"}}}}, "$_DFFSR_PNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1733.1-1744.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFSR_PNN_": {"type": "$_DFFSR_PNN_", "port_directions": {"C": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1734.7-1734.8"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1734.16-1734.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1735.12-1735.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1734.13-1734.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1734.10-1734.11"}}}}, "$_DFFSR_PNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1761.1-1772.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFSR_PNP_": {"type": "$_DFFSR_PNP_", "port_directions": {"C": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1762.7-1762.8"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1762.16-1762.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1763.12-1763.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1762.13-1762.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1762.10-1762.11"}}}}, "$_DFFSR_PPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1789.1-1800.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFSR_PPN_": {"type": "$_DFFSR_PPN_", "port_directions": {"C": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1790.7-1790.8"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1790.16-1790.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1791.12-1791.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1790.13-1790.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1790.10-1790.11"}}}}, "$_DFFSR_PPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1817.1-1828.10"}, "ports": {"C": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DFFSR_PPP_": {"type": "$_DFFSR_PPP_", "port_directions": {"C": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"C": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1818.7-1818.8"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1818.16-1818.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1819.12-1819.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1818.13-1818.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:1818.10-1818.11"}}}}, "$_DFF_NN0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:731.1-740.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFF_NN0_": {"type": "$_DFF_NN0_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:732.10-732.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:732.7-732.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:733.12-733.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:732.13-732.14"}}}}, "$_DFF_NN1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:755.1-764.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFF_NN1_": {"type": "$_DFF_NN1_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:756.10-756.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:756.7-756.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:757.12-757.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:756.13-756.14"}}}}, "$_DFF_NP0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:779.1-788.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFF_NP0_": {"type": "$_DFF_NP0_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:780.10-780.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:780.7-780.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:781.12-781.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:780.13-780.14"}}}}, "$_DFF_NP1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:803.1-812.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFF_NP1_": {"type": "$_DFF_NP1_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:804.10-804.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:804.7-804.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:805.12-805.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:804.13-804.14"}}}}, "$_DFF_N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:610.1-616.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "Q": {"direction": "output", "bits": [4]}}, "cells": {"$_DFF_N_": {"type": "$_DFF_N_", "port_directions": {"D": "input", "C": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "Q": [4]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:611.10-611.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:611.7-611.8"}}, "Q": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:612.12-612.13"}}}}, "$_DFF_PN0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:827.1-836.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFF_PN0_": {"type": "$_DFF_PN0_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:828.10-828.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:828.7-828.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:829.12-829.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:828.13-828.14"}}}}, "$_DFF_PN1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:851.1-860.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFF_PN1_": {"type": "$_DFF_PN1_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:852.10-852.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:852.7-852.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:853.12-853.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:852.13-852.14"}}}}, "$_DFF_PP0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:875.1-884.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFF_PP0_": {"type": "$_DFF_PP0_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:876.10-876.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:876.7-876.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:877.12-877.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:876.13-876.14"}}}}, "$_DFF_PP1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:899.1-908.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DFF_PP1_": {"type": "$_DFF_PP1_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:900.10-900.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:900.7-900.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:901.12-901.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:900.13-900.14"}}}}, "$_DFF_P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:630.1-636.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "Q": {"direction": "output", "bits": [4]}}, "cells": {"$_DFF_P_": {"type": "$_DFF_P_", "port_directions": {"D": "input", "C": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "Q": [4]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:631.10-631.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:631.7-631.8"}}, "Q": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:632.12-632.13"}}}}, "$_DLATCHSR_NNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3551.1-3562.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DLATCHSR_NNN_": {"type": "$_DLATCHSR_NNN_", "port_directions": {"E": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3552.16-3552.17"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3552.7-3552.8"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3553.12-3553.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3552.13-3552.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3552.10-3552.11"}}}}, "$_DLATCHSR_NNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3579.1-3590.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DLATCHSR_NNP_": {"type": "$_DLATCHSR_NNP_", "port_directions": {"E": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3580.16-3580.17"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3580.7-3580.8"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3581.12-3581.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3580.13-3580.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3580.10-3580.11"}}}}, "$_DLATCHSR_NPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3607.1-3618.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DLATCHSR_NPN_": {"type": "$_DLATCHSR_NPN_", "port_directions": {"E": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3608.16-3608.17"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3608.7-3608.8"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3609.12-3609.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3608.13-3608.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3608.10-3608.11"}}}}, "$_DLATCHSR_NPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3635.1-3646.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DLATCHSR_NPP_": {"type": "$_DLATCHSR_NPP_", "port_directions": {"E": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3636.16-3636.17"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3636.7-3636.8"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3637.12-3637.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3636.13-3636.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3636.10-3636.11"}}}}, "$_DLATCHSR_PNN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3663.1-3674.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DLATCHSR_PNN_": {"type": "$_DLATCHSR_PNN_", "port_directions": {"E": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3664.16-3664.17"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3664.7-3664.8"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3665.12-3665.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3664.13-3664.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3664.10-3664.11"}}}}, "$_DLATCHSR_PNP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3691.1-3702.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DLATCHSR_PNP_": {"type": "$_DLATCHSR_PNP_", "port_directions": {"E": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3692.16-3692.17"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3692.7-3692.8"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3693.12-3693.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3692.13-3692.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3692.10-3692.11"}}}}, "$_DLATCHSR_PPN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3719.1-3730.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DLATCHSR_PPN_": {"type": "$_DLATCHSR_PPN_", "port_directions": {"E": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3720.16-3720.17"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3720.7-3720.8"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3721.12-3721.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3720.13-3720.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3720.10-3720.11"}}}}, "$_DLATCHSR_PPP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3747.1-3758.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "S": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_DLATCHSR_PPP_": {"type": "$_DLATCHSR_PPP_", "port_directions": {"E": "input", "S": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "S": [3], "R": [4], "D": [5], "Q": [6]}}}, "netnames": {"D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3748.16-3748.17"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3748.7-3748.8"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3749.12-3749.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3748.13-3748.14"}}, "S": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3748.10-3748.11"}}}}, "$_DLATCH_NN0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3357.1-3366.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "D": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DLATCH_NN0_": {"type": "$_DLATCH_NN0_", "port_directions": {"E": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "R": [3], "D": [4], "Q": [5]}}}, "netnames": {"D": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3358.13-3358.14"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3358.7-3358.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3359.12-3359.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3358.10-3358.11"}}}}, "$_DLATCH_NN1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3381.1-3390.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "D": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DLATCH_NN1_": {"type": "$_DLATCH_NN1_", "port_directions": {"E": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "R": [3], "D": [4], "Q": [5]}}}, "netnames": {"D": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3382.13-3382.14"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3382.7-3382.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3383.12-3383.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3382.10-3382.11"}}}}, "$_DLATCH_NP0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3405.1-3414.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "D": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DLATCH_NP0_": {"type": "$_DLATCH_NP0_", "port_directions": {"E": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "R": [3], "D": [4], "Q": [5]}}}, "netnames": {"D": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3406.13-3406.14"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3406.7-3406.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3407.12-3407.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3406.10-3406.11"}}}}, "$_DLATCH_NP1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3429.1-3438.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "D": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DLATCH_NP1_": {"type": "$_DLATCH_NP1_", "port_directions": {"E": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "R": [3], "D": [4], "Q": [5]}}}, "netnames": {"D": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3430.13-3430.14"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3430.7-3430.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3431.12-3431.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3430.10-3430.11"}}}}, "$_DLATCH_N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3314.1-3321.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "D": {"direction": "input", "bits": [3]}, "Q": {"direction": "output", "bits": [4]}}, "cells": {"$_DLATCH_N_": {"type": "$_DLATCH_N_", "port_directions": {"E": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "D": [3], "Q": [4]}}}, "netnames": {"D": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3315.10-3315.11"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3315.7-3315.8"}}, "Q": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3316.12-3316.13"}}}}, "$_DLATCH_PN0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3453.1-3462.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "D": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DLATCH_PN0_": {"type": "$_DLATCH_PN0_", "port_directions": {"E": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "R": [3], "D": [4], "Q": [5]}}}, "netnames": {"D": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3454.13-3454.14"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3454.7-3454.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3455.12-3455.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3454.10-3454.11"}}}}, "$_DLATCH_PN1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3477.1-3486.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "D": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DLATCH_PN1_": {"type": "$_DLATCH_PN1_", "port_directions": {"E": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "R": [3], "D": [4], "Q": [5]}}}, "netnames": {"D": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3478.13-3478.14"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3478.7-3478.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3479.12-3479.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3478.10-3478.11"}}}}, "$_DLATCH_PP0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3501.1-3510.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "D": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DLATCH_PP0_": {"type": "$_DLATCH_PP0_", "port_directions": {"E": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "R": [3], "D": [4], "Q": [5]}}}, "netnames": {"D": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3502.13-3502.14"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3502.7-3502.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3503.12-3503.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3502.10-3502.11"}}}}, "$_DLATCH_PP1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3525.1-3534.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "D": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_DLATCH_PP1_": {"type": "$_DLATCH_PP1_", "port_directions": {"E": "input", "R": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "R": [3], "D": [4], "Q": [5]}}}, "netnames": {"D": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3526.13-3526.14"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3526.7-3526.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3527.12-3527.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3526.10-3526.11"}}}}, "$_DLATCH_P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3335.1-3342.10"}, "ports": {"E": {"direction": "input", "bits": [2]}, "D": {"direction": "input", "bits": [3]}, "Q": {"direction": "output", "bits": [4]}}, "cells": {"$_DLATCH_P_": {"type": "$_DLATCH_P_", "port_directions": {"E": "input", "D": "input", "Q": "output"}, "connections": {"E": [2], "D": [3], "Q": [4]}}}, "netnames": {"D": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3336.10-3336.11"}}, "E": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3336.7-3336.8"}}, "Q": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3337.12-3337.13"}}}}, "$_MUX16__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:336.1-347.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "C": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "F": {"direction": "input", "bits": [7]}, "G": {"direction": "input", "bits": [8]}, "H": {"direction": "input", "bits": [9]}, "I": {"direction": "input", "bits": [10]}, "J": {"direction": "input", "bits": [11]}, "K": {"direction": "input", "bits": [12]}, "L": {"direction": "input", "bits": [13]}, "M": {"direction": "input", "bits": [14]}, "N": {"direction": "input", "bits": [15]}, "O": {"direction": "input", "bits": [16]}, "P": {"direction": "input", "bits": [17]}, "S": {"direction": "input", "bits": [18]}, "T": {"direction": "input", "bits": [19]}, "U": {"direction": "input", "bits": [20]}, "V": {"direction": "input", "bits": [21]}, "Y": {"direction": "output", "bits": [22]}}, "cells": {"$_MUX16_": {"type": "$_MUX16_", "port_directions": {"A": "input", "B": "input", "C": "input", "D": "input", "E": "input", "F": "input", "G": "input", "H": "input", "I": "input", "J": "input", "K": "input", "L": "input", "M": "input", "N": "input", "O": "input", "P": "input", "S": "input", "T": "input", "U": "input", "V": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "C": [4], "D": [5], "E": [6], "F": [7], "G": [8], "H": [9], "I": [10], "J": [11], "K": [12], "L": [13], "M": [14], "N": [15], "O": [16], "P": [17], "S": [18], "T": [19], "U": [20], "V": [21], "Y": [22]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.7-337.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.10-337.11"}}, "C": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.13-337.14"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.16-337.17"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.19-337.20"}}, "F": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.22-337.23"}}, "G": {"hide_name": 0, "bits": [8], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.25-337.26"}}, "H": {"hide_name": 0, "bits": [9], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.28-337.29"}}, "I": {"hide_name": 0, "bits": [10], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.31-337.32"}}, "J": {"hide_name": 0, "bits": [11], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.34-337.35"}}, "K": {"hide_name": 0, "bits": [12], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.37-337.38"}}, "L": {"hide_name": 0, "bits": [13], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.40-337.41"}}, "M": {"hide_name": 0, "bits": [14], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.43-337.44"}}, "N": {"hide_name": 0, "bits": [15], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.46-337.47"}}, "O": {"hide_name": 0, "bits": [16], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.49-337.50"}}, "P": {"hide_name": 0, "bits": [17], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.52-337.53"}}, "S": {"hide_name": 0, "bits": [18], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.55-337.56"}}, "T": {"hide_name": 0, "bits": [19], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.58-337.59"}}, "U": {"hide_name": 0, "bits": [20], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.61-337.62"}}, "V": {"hide_name": 0, "bits": [21], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:337.64-337.65"}}, "Y": {"hide_name": 0, "bits": [22], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:338.8-338.9"}}}}, "$_MUX4__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:276.1-281.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "C": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "S": {"direction": "input", "bits": [6]}, "T": {"direction": "input", "bits": [7]}, "Y": {"direction": "output", "bits": [8]}}, "cells": {"$_MUX4_": {"type": "$_MUX4_", "port_directions": {"A": "input", "B": "input", "C": "input", "D": "input", "S": "input", "T": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "C": [4], "D": [5], "S": [6], "T": [7], "Y": [8]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:277.7-277.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:277.10-277.11"}}, "C": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:277.13-277.14"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:277.16-277.17"}}, "S": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:277.19-277.20"}}, "T": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:277.22-277.23"}}, "Y": {"hide_name": 0, "bits": [8], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:278.8-278.9"}}}}, "$_MUX8__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:301.1-308.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "C": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "E": {"direction": "input", "bits": [6]}, "F": {"direction": "input", "bits": [7]}, "G": {"direction": "input", "bits": [8]}, "H": {"direction": "input", "bits": [9]}, "S": {"direction": "input", "bits": [10]}, "T": {"direction": "input", "bits": [11]}, "U": {"direction": "input", "bits": [12]}, "Y": {"direction": "output", "bits": [13]}}, "cells": {"$_MUX8_": {"type": "$_MUX8_", "port_directions": {"A": "input", "B": "input", "C": "input", "D": "input", "E": "input", "F": "input", "G": "input", "H": "input", "S": "input", "T": "input", "U": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "C": [4], "D": [5], "E": [6], "F": [7], "G": [8], "H": [9], "S": [10], "T": [11], "U": [12], "Y": [13]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.7-302.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.10-302.11"}}, "C": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.13-302.14"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.16-302.17"}}, "E": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.19-302.20"}}, "F": {"hide_name": 0, "bits": [7], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.22-302.23"}}, "G": {"hide_name": 0, "bits": [8], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.25-302.26"}}, "H": {"hide_name": 0, "bits": [9], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.28-302.29"}}, "S": {"hide_name": 0, "bits": [10], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.31-302.32"}}, "T": {"hide_name": 0, "bits": [11], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.34-302.35"}}, "U": {"hide_name": 0, "bits": [12], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:302.37-302.38"}}, "Y": {"hide_name": 0, "bits": [13], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:303.8-303.9"}}}}, "$_MUX__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:236.1-240.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "S": {"direction": "input", "bits": [4]}, "Y": {"direction": "output", "bits": [5]}}, "cells": {"$_MUX_": {"type": "$_MUX_", "port_directions": {"A": "input", "B": "input", "S": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "S": [4], "Y": [5]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:237.7-237.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:237.10-237.11"}}, "S": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:237.13-237.14"}}, "Y": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:238.8-238.9"}}}}, "$_NAND__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:98.1-102.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "Y": {"direction": "output", "bits": [4]}}, "cells": {"$_NAND_": {"type": "$_NAND_", "port_directions": {"A": "input", "B": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "Y": [4]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:99.7-99.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:99.10-99.11"}}, "Y": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:100.8-100.9"}}}}, "$_NMUX__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:256.1-260.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "S": {"direction": "input", "bits": [4]}, "Y": {"direction": "output", "bits": [5]}}, "cells": {"$_NMUX_": {"type": "$_NMUX_", "port_directions": {"A": "input", "B": "input", "S": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "S": [4], "Y": [5]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:257.7-257.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:257.10-257.11"}}, "S": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:257.13-257.14"}}, "Y": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:258.8-258.9"}}}}, "$_NOR__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:138.1-142.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "Y": {"direction": "output", "bits": [4]}}, "cells": {"$_NOR_": {"type": "$_NOR_", "port_directions": {"A": "input", "B": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "Y": [4]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:139.7-139.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:139.10-139.11"}}, "Y": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:140.8-140.9"}}}}, "$_NOT__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:58.1-62.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "Y": {"direction": "output", "bits": [3]}}, "cells": {"$_NOT_": {"type": "$_NOT_", "port_directions": {"A": "input", "Y": "output"}, "connections": {"A": [2], "Y": [3]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:59.7-59.8"}}, "Y": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:60.8-60.9"}}}}, "$_OAI3__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:391.1-395.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "C": {"direction": "input", "bits": [4]}, "Y": {"direction": "output", "bits": [5]}}, "cells": {"$_OAI3_": {"type": "$_OAI3_", "port_directions": {"A": "input", "B": "input", "C": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "C": [4], "Y": [5]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:392.7-392.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:392.10-392.11"}}, "C": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:392.13-392.14"}}, "Y": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:393.8-393.9"}}}}, "$_OAI4__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:455.1-459.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "C": {"direction": "input", "bits": [4]}, "D": {"direction": "input", "bits": [5]}, "Y": {"direction": "output", "bits": [6]}}, "cells": {"$_OAI4_": {"type": "$_OAI4_", "port_directions": {"A": "input", "B": "input", "C": "input", "D": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "C": [4], "D": [5], "Y": [6]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:456.7-456.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:456.10-456.11"}}, "C": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:456.13-456.14"}}, "D": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:456.16-456.17"}}, "Y": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:457.8-457.9"}}}}, "$_ORNOT__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:218.1-222.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "Y": {"direction": "output", "bits": [4]}}, "cells": {"$_ORNOT_": {"type": "$_ORNOT_", "port_directions": {"A": "input", "B": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "Y": [4]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:219.7-219.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:219.10-219.11"}}, "Y": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:220.8-220.9"}}}}, "$_OR__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:118.1-122.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "Y": {"direction": "output", "bits": [4]}}, "cells": {"$_OR_": {"type": "$_OR_", "port_directions": {"A": "input", "B": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "Y": [4]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:119.7-119.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:119.10-119.11"}}, "Y": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:120.8-120.9"}}}}, "$_SDFFCE_NN0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2884.1-2895.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_NN0N_": {"type": "$_SDFFCE_NN0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2885.10-2885.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2885.7-2885.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2885.16-2885.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2886.12-2886.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2885.13-2885.14"}}}}, "$_SDFFCE_NN0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2911.1-2922.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_NN0P_": {"type": "$_SDFFCE_NN0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2912.10-2912.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2912.7-2912.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2912.16-2912.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2913.12-2913.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2912.13-2912.14"}}}}, "$_SDFFCE_NN1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2938.1-2949.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_NN1N_": {"type": "$_SDFFCE_NN1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2939.10-2939.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2939.7-2939.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2939.16-2939.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2940.12-2940.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2939.13-2939.14"}}}}, "$_SDFFCE_NN1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2965.1-2976.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_NN1P_": {"type": "$_SDFFCE_NN1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2966.10-2966.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2966.7-2966.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2966.16-2966.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2967.12-2967.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2966.13-2966.14"}}}}, "$_SDFFCE_NP0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2992.1-3003.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_NP0N_": {"type": "$_SDFFCE_NP0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2993.10-2993.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2993.7-2993.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2993.16-2993.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2994.12-2994.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2993.13-2993.14"}}}}, "$_SDFFCE_NP0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3019.1-3030.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_NP0P_": {"type": "$_SDFFCE_NP0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3020.10-3020.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3020.7-3020.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3020.16-3020.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3021.12-3021.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3020.13-3020.14"}}}}, "$_SDFFCE_NP1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3046.1-3057.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_NP1N_": {"type": "$_SDFFCE_NP1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3047.10-3047.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3047.7-3047.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3047.16-3047.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3048.12-3048.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3047.13-3047.14"}}}}, "$_SDFFCE_NP1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3073.1-3084.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_NP1P_": {"type": "$_SDFFCE_NP1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3074.10-3074.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3074.7-3074.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3074.16-3074.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3075.12-3075.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3074.13-3074.14"}}}}, "$_SDFFCE_PN0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3100.1-3111.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_PN0N_": {"type": "$_SDFFCE_PN0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3101.10-3101.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3101.7-3101.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3101.16-3101.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3102.12-3102.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3101.13-3101.14"}}}}, "$_SDFFCE_PN0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3127.1-3138.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_PN0P_": {"type": "$_SDFFCE_PN0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3128.10-3128.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3128.7-3128.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3128.16-3128.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3129.12-3129.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3128.13-3128.14"}}}}, "$_SDFFCE_PN1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3154.1-3165.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_PN1N_": {"type": "$_SDFFCE_PN1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3155.10-3155.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3155.7-3155.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3155.16-3155.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3156.12-3156.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3155.13-3155.14"}}}}, "$_SDFFCE_PN1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3181.1-3192.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_PN1P_": {"type": "$_SDFFCE_PN1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3182.10-3182.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3182.7-3182.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3182.16-3182.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3183.12-3183.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3182.13-3182.14"}}}}, "$_SDFFCE_PP0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3208.1-3219.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_PP0N_": {"type": "$_SDFFCE_PP0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3209.10-3209.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3209.7-3209.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3209.16-3209.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3210.12-3210.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3209.13-3209.14"}}}}, "$_SDFFCE_PP0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3235.1-3246.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_PP0P_": {"type": "$_SDFFCE_PP0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3236.10-3236.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3236.7-3236.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3236.16-3236.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3237.12-3237.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3236.13-3236.14"}}}}, "$_SDFFCE_PP1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3262.1-3273.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_PP1N_": {"type": "$_SDFFCE_PP1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3263.10-3263.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3263.7-3263.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3263.16-3263.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3264.12-3264.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3263.13-3263.14"}}}}, "$_SDFFCE_PP1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3289.1-3300.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFCE_PP1P_": {"type": "$_SDFFCE_PP1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3290.10-3290.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3290.7-3290.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3290.16-3290.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3291.12-3291.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:3290.13-3290.14"}}}}, "$_SDFFE_NN0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2484.1-2493.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_NN0N_": {"type": "$_SDFFE_NN0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2485.10-2485.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2485.7-2485.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2485.16-2485.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2486.12-2486.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2485.13-2485.14"}}}}, "$_SDFFE_NN0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2509.1-2518.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_NN0P_": {"type": "$_SDFFE_NN0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2510.10-2510.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2510.7-2510.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2510.16-2510.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2511.12-2511.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2510.13-2510.14"}}}}, "$_SDFFE_NN1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2534.1-2543.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_NN1N_": {"type": "$_SDFFE_NN1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2535.10-2535.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2535.7-2535.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2535.16-2535.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2536.12-2536.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2535.13-2535.14"}}}}, "$_SDFFE_NN1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2559.1-2568.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_NN1P_": {"type": "$_SDFFE_NN1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2560.10-2560.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2560.7-2560.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2560.16-2560.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2561.12-2561.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2560.13-2560.14"}}}}, "$_SDFFE_NP0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2584.1-2593.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_NP0N_": {"type": "$_SDFFE_NP0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2585.10-2585.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2585.7-2585.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2585.16-2585.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2586.12-2586.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2585.13-2585.14"}}}}, "$_SDFFE_NP0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2609.1-2618.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_NP0P_": {"type": "$_SDFFE_NP0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2610.10-2610.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2610.7-2610.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2610.16-2610.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2611.12-2611.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2610.13-2610.14"}}}}, "$_SDFFE_NP1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2634.1-2643.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_NP1N_": {"type": "$_SDFFE_NP1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2635.10-2635.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2635.7-2635.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2635.16-2635.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2636.12-2636.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2635.13-2635.14"}}}}, "$_SDFFE_NP1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2659.1-2668.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_NP1P_": {"type": "$_SDFFE_NP1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2660.10-2660.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2660.7-2660.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2660.16-2660.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2661.12-2661.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2660.13-2660.14"}}}}, "$_SDFFE_PN0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2684.1-2693.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_PN0N_": {"type": "$_SDFFE_PN0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2685.10-2685.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2685.7-2685.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2685.16-2685.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2686.12-2686.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2685.13-2685.14"}}}}, "$_SDFFE_PN0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2709.1-2718.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_PN0P_": {"type": "$_SDFFE_PN0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2710.10-2710.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2710.7-2710.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2710.16-2710.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2711.12-2711.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2710.13-2710.14"}}}}, "$_SDFFE_PN1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2734.1-2743.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_PN1N_": {"type": "$_SDFFE_PN1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2735.10-2735.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2735.7-2735.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2735.16-2735.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2736.12-2736.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2735.13-2735.14"}}}}, "$_SDFFE_PN1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2759.1-2768.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_PN1P_": {"type": "$_SDFFE_PN1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2760.10-2760.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2760.7-2760.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2760.16-2760.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2761.12-2761.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2760.13-2760.14"}}}}, "$_SDFFE_PP0N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2784.1-2793.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_PP0N_": {"type": "$_SDFFE_PP0N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2785.10-2785.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2785.7-2785.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2785.16-2785.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2786.12-2786.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2785.13-2785.14"}}}}, "$_SDFFE_PP0P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2809.1-2818.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_PP0P_": {"type": "$_SDFFE_PP0P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2810.10-2810.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2810.7-2810.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2810.16-2810.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2811.12-2811.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2810.13-2810.14"}}}}, "$_SDFFE_PP1N__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2834.1-2843.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_PP1N_": {"type": "$_SDFFE_PP1N_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2835.10-2835.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2835.7-2835.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2835.16-2835.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2836.12-2836.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2835.13-2835.14"}}}}, "$_SDFFE_PP1P__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2859.1-2868.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "E": {"direction": "input", "bits": [5]}, "Q": {"direction": "output", "bits": [6]}}, "cells": {"$_SDFFE_PP1P_": {"type": "$_SDFFE_PP1P_", "port_directions": {"D": "input", "C": "input", "R": "input", "E": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "E": [5], "Q": [6]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2860.10-2860.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2860.7-2860.8"}}, "E": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2860.16-2860.17"}}, "Q": {"hide_name": 0, "bits": [6], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2861.12-2861.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2860.13-2860.14"}}}}, "$_SDFF_NN0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2291.1-2300.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_SDFF_NN0_": {"type": "$_SDFF_NN0_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2292.10-2292.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2292.7-2292.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2293.12-2293.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2292.13-2292.14"}}}}, "$_SDFF_NN1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2315.1-2324.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_SDFF_NN1_": {"type": "$_SDFF_NN1_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2316.10-2316.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2316.7-2316.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2317.12-2317.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2316.13-2316.14"}}}}, "$_SDFF_NP0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2339.1-2348.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_SDFF_NP0_": {"type": "$_SDFF_NP0_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2340.10-2340.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2340.7-2340.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2341.12-2341.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2340.13-2340.14"}}}}, "$_SDFF_NP1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2363.1-2372.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_SDFF_NP1_": {"type": "$_SDFF_NP1_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2364.10-2364.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2364.7-2364.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2365.12-2365.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2364.13-2364.14"}}}}, "$_SDFF_PN0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2387.1-2396.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_SDFF_PN0_": {"type": "$_SDFF_PN0_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2388.10-2388.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2388.7-2388.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2389.12-2389.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2388.13-2388.14"}}}}, "$_SDFF_PN1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2411.1-2420.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_SDFF_PN1_": {"type": "$_SDFF_PN1_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2412.10-2412.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2412.7-2412.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2413.12-2413.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2412.13-2412.14"}}}}, "$_SDFF_PP0__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2435.1-2444.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_SDFF_PP0_": {"type": "$_SDFF_PP0_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2436.10-2436.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2436.7-2436.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2437.12-2437.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2436.13-2436.14"}}}}, "$_SDFF_PP1__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2459.1-2468.10"}, "ports": {"D": {"direction": "input", "bits": [2]}, "C": {"direction": "input", "bits": [3]}, "R": {"direction": "input", "bits": [4]}, "Q": {"direction": "output", "bits": [5]}}, "cells": {"$_SDFF_PP1_": {"type": "$_SDFF_PP1_", "port_directions": {"D": "input", "C": "input", "R": "input", "Q": "output"}, "connections": {"D": [2], "C": [3], "R": [4], "Q": [5]}}}, "netnames": {"C": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2460.10-2460.11"}}, "D": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2460.7-2460.8"}}, "Q": {"hide_name": 0, "bits": [5], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2461.12-2461.13"}}, "R": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:2460.13-2460.14"}}}}, "$_SR_NN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:497.1-506.10"}, "ports": {"S": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "Q": {"direction": "output", "bits": [4]}}, "cells": {"$_SR_NN_": {"type": "$_SR_NN_", "port_directions": {"S": "input", "R": "input", "Q": "output"}, "connections": {"S": [2], "R": [3], "Q": [4]}}}, "netnames": {"Q": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:499.12-499.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:498.10-498.11"}}, "S": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:498.7-498.8"}}}}, "$_SR_NP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:521.1-530.10"}, "ports": {"S": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "Q": {"direction": "output", "bits": [4]}}, "cells": {"$_SR_NP_": {"type": "$_SR_NP_", "port_directions": {"S": "input", "R": "input", "Q": "output"}, "connections": {"S": [2], "R": [3], "Q": [4]}}}, "netnames": {"Q": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:523.12-523.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:522.10-522.11"}}, "S": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:522.7-522.8"}}}}, "$_SR_PN__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:545.1-554.10"}, "ports": {"S": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "Q": {"direction": "output", "bits": [4]}}, "cells": {"$_SR_PN_": {"type": "$_SR_PN_", "port_directions": {"S": "input", "R": "input", "Q": "output"}, "connections": {"S": [2], "R": [3], "Q": [4]}}}, "netnames": {"Q": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:547.12-547.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:546.10-546.11"}}, "S": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:546.7-546.8"}}}}, "$_SR_PP__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:569.1-578.10"}, "ports": {"S": {"direction": "input", "bits": [2]}, "R": {"direction": "input", "bits": [3]}, "Q": {"direction": "output", "bits": [4]}}, "cells": {"$_SR_PP_": {"type": "$_SR_PP_", "port_directions": {"S": "input", "R": "input", "Q": "output"}, "connections": {"S": [2], "R": [3], "Q": [4]}}}, "netnames": {"Q": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:571.12-571.13"}}, "R": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:570.10-570.11"}}, "S": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:570.7-570.8"}}}}, "$_TBUF__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:473.1-477.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "E": {"direction": "input", "bits": [3]}, "Y": {"direction": "output", "bits": [4]}}, "cells": {"$_TBUF_": {"type": "$_TBUF_", "port_directions": {"A": "input", "E": "input", "Y": "output"}, "connections": {"A": [2], "E": [3], "Y": [4]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:474.7-474.8"}}, "E": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:474.10-474.11"}}, "Y": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:475.8-475.9"}}}}, "$_XNOR__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:178.1-182.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "Y": {"direction": "output", "bits": [4]}}, "cells": {"$_XNOR_": {"type": "$_XNOR_", "port_directions": {"A": "input", "B": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "Y": [4]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:179.7-179.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:179.10-179.11"}}, "Y": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:180.8-180.9"}}}}, "$_XOR__WRAPPER": {"attributes": {"blackbox": "00000000000000000000000000000001", "cells_not_processed": "00000000000000000000000000000001", "src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:158.1-162.10"}, "ports": {"A": {"direction": "input", "bits": [2]}, "B": {"direction": "input", "bits": [3]}, "Y": {"direction": "output", "bits": [4]}}, "cells": {"$_XOR_": {"type": "$_XOR_", "port_directions": {"A": "input", "B": "input", "Y": "output"}, "connections": {"A": [2], "B": [3], "Y": [4]}}}, "netnames": {"A": {"hide_name": 0, "bits": [2], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:159.7-159.8"}}, "B": {"hide_name": 0, "bits": [3], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:159.10-159.11"}}, "Y": {"hide_name": 0, "bits": [4], "attributes": {"src": "/opt/oss-cad-suite/latest/share/yosys/simcells.v:160.8-160.9"}}}}}} diff --git a/crates/arbolta/tests/deps/simlib_wrappers.json b/crates/arbolta/tests/deps/simlib_wrappers.json new file mode 100644 index 0000000..e37d309 --- /dev/null +++ b/crates/arbolta/tests/deps/simlib_wrappers.json @@ -0,0 +1,48 @@ +{ + "creator": "Yosys 0.14+51 (git sha1 286caa09b, gcc 9.3.0-13 -fPIC -Os)", + "modules": { + "$add_wrapper": { + "ports": { + "A": { + "direction": "input", + "bits": [ 2, 3, 4, 5, 6, 7, 8, 9 ] + }, + "B": { + "direction": "input", + "bits": [ 10, 11, 12, 13, 14, 15, 16, 17 ] + }, + "Y": { + "direction": "output", + "bits": [ 18, 19, 20, 21, 22, 23, 24, 25 ] + } + }, + "cells": { + "$1": { + "type": "$add", + "parameters": { + "A_SIGNED": "00000000000000000000000000000001", + "A_WIDTH": "00000000000000000000000000010000", + "B_SIGNED": "00000000000000000000000000000001", + "B_WIDTH": "00000000000000000000000000010000", + "Y_WIDTH": "00000000000000000000000000010000" + }, + "port_directions": { + "A": "input", + "B": "input", + "Y": "output" + }, + "connections": { + "A": [ 2, 3, 4, 5, 6, 7, 8, 9 ], + "B": [ 10, 11, 12, 13, 14, 15, 16, 17 ], + "Y": [ 18, 19, 20, 21, 22, 23, 24, 25 ] + } + } + }, + "netnames": { + "A": {"bits": [ 2, 3, 4, 5, 6, 7, 8, 9 ]}, + "B": {"bits": [ 10, 11, 12, 13, 14, 15, 16, 17 ]}, + "Y": {"bits": [ 18, 19, 20, 21, 22, 23, 24, 25 ]} + } + } + } +} diff --git a/crates/arbolta/tests/deps/simlib_wrappers.sv b/crates/arbolta/tests/deps/simlib_wrappers.sv new file mode 100644 index 0000000..4926296 --- /dev/null +++ b/crates/arbolta/tests/deps/simlib_wrappers.sv @@ -0,0 +1,54 @@ +`include "/opt/oss-cad-suite/share/yosys/simlib.v" + +// module not_wrapper ( +// A, +// Y +// ); + +// parameter A_SIGNED = 0; +// parameter A_WIDTH = 0; +// parameter Y_WIDTH = 0; + +// input [A_WIDTH-1:0] A; +// output [Y_WIDTH-1:0] Y; + +// \$not #( +// .A_SIGNED(A_SIGNED), +// .A_WIDTH (A_WIDTH), +// .Y_WIDTH (Y_WIDTH) +// ) _TECHMAP_REPLACE_ ( +// .A(A), +// .Y(Y) +// ); + +// endmodule + +module \$add_wrapper ( + A, + B, + Y +); + + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 0; + parameter B_WIDTH = 0; + parameter Y_WIDTH = 0; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + \$add #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH (A_WIDTH), + .B_WIDTH (B_WIDTH), + .Y_WIDTH (Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A(A), + .B(B), + .Y(Y) + ); + +endmodule diff --git a/crates/arbolta/tests/generate_deps.py b/crates/arbolta/tests/generate_deps.py new file mode 100644 index 0000000..82fcfc7 --- /dev/null +++ b/crates/arbolta/tests/generate_deps.py @@ -0,0 +1,63 @@ +import copy +import json +import subprocess +from pathlib import Path + + +def generate_simcells_netlist(simcells_verilog: Path, netlist: Path): + passes = f""" + read_verilog -sv -icells -lib {simcells_verilog}; + proc; + clean; + autoname; + setundef -zero; + flatten -scopename; + write_json {netlist}; + """ + args = ["yosys", "-p", passes] + + result = subprocess.run( + args, capture_output=True, timeout=60, text=True, encoding="utf-8" + ) + assert result.returncode == 0, result.stderr + + +def clean_simcells_netlist(netlist_path: Path, new_netlist_path: Path): + with open(netlist_path, "r") as f: + netlist = json.load(f) + + new_netlist = {k: v for k, v in netlist.items() if k != "modules"} + new_netlist["modules"] = {} + + for module_name, module in netlist["modules"].items(): + new_module_name = f"{module_name}_WRAPPER" + new_netlist["modules"][new_module_name] = copy.deepcopy(module) + + if len(module["cells"]) > 0: + continue + + module_cell = { + "type": module_name, + "port_directions": {}, + "connections": {}, + } + + for port_name, port_info in module["ports"].items(): + # print(port_info) + module_cell["port_directions"][port_name] = port_info["direction"] + module_cell["connections"][port_name] = port_info["bits"] + + new_netlist["modules"][new_module_name]["cells"] = {module_name: module_cell} + + with open(new_netlist_path, "w") as f: + json.dump(new_netlist, f) + + # print(netlist) + + +if __name__ == "__main__": + rtl_path = Path("/opt/oss-cad-suite/latest/share/yosys/simcells.v") + netlist_path = Path("./deps/simcells_wrappers.json") + + generate_simcells_netlist(rtl_path, netlist_path) + clean_simcells_netlist(netlist_path, netlist_path) diff --git a/crates/arbolta/tests/helpers.rs b/crates/arbolta/tests/helpers.rs new file mode 100644 index 0000000..9d8e8d4 --- /dev/null +++ b/crates/arbolta/tests/helpers.rs @@ -0,0 +1,97 @@ +use arbolta::yosys::*; +use indexmap::*; + +fn allocate_nets(offset: Option, widths: &[usize]) -> Vec> { + let mut all_nets: Vec> = vec![]; + let offset = offset.unwrap_or(0); + + for width in widths { + let start: usize = match all_nets.last() { + Some(last) => last[last.len() - 1] + 1, + None => offset, + }; + + all_nets.push((start..start + width).collect()); + } + + let mut bits = vec![]; + for nets in all_nets { + let new_bits: Vec = nets.iter().map(|&n| BitVal::N(n)).collect(); + bits.push(new_bits) + } + + bits +} + +pub fn int_to_attr(x: u32) -> AttributeVal { + AttributeVal::S(format!("{:032b}", x)) +} + +pub fn build_netlist( + cell_type: &str, + module_name: &'static str, + parameters: IndexMap<&str, AttributeVal>, + ports: IndexMap<&str, (PortDirection, usize)>, // width +) -> (Netlist, TopoOrder<'static>) { + let mut netlist = Netlist::new("test"); + + let widths: Vec = ports.values().map(|(_, w)| *w).collect(); + let nets = allocate_nets(Some(2), &widths); + + let mut actual_parameters = IndexMap::new(); + for (param_name, val) in parameters { + actual_parameters.insert(param_name.to_string(), val); + } + + let mut port_directions = IndexMap::new(); + for (port_name, port_info) in &ports { + port_directions.insert(port_name.to_string(), port_info.0); + } + + let mut connections = IndexMap::new(); + for (i, port_name) in ports.keys().enumerate() { + connections.insert(port_name.to_string(), nets[i].clone()); + } + + let cell = Cell { + cell_type: cell_type.into(), + parameters: actual_parameters, + port_directions, + connections, + ..Default::default() + }; + + let mut actual_ports = IndexMap::new(); + let mut netnames = IndexMap::new(); + for (i, (port_name, port_info)) in ports.iter().enumerate() { + let new_port = Port { + direction: port_info.0, + bits: nets[i].clone(), + offset: 0, + upto: 0, + signed: 0, + }; + let netname = Netname { + bits: nets[i].clone(), + ..Default::default() + }; + actual_ports.insert(port_name.to_string(), new_port); + netnames.insert(port_name.to_string(), netname); + } + + let module = Module { + attributes: indexmap! { + "top".into() => int_to_attr(1) + }, + ports: actual_ports, + netnames, + cells: indexmap! {"$1".into() => cell}, + ..Default::default() + }; + + netlist.modules.insert(module_name.to_string(), module); + + let torder = TopoOrder::from([(module_name, vec!["$1"])]); + + (netlist, torder) +} diff --git a/crates/arbolta/tests/test_bit.rs b/crates/arbolta/tests/test_bit.rs index 121fa3f..e74465a 100644 --- a/crates/arbolta/tests/test_bit.rs +++ b/crates/arbolta/tests/test_bit.rs @@ -1,72 +1,64 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding // SPDX-License-Identifier: MIT use arbolta::bit::Bit; -use std::str::FromStr; - use rstest::rstest; #[rstest] -#[case("0", Bit::Zero)] -#[case("1", Bit::One)] -fn test_bit_from_str(#[case] val: String, #[case] expected: Bit) { - assert_eq!(Bit::from_str(&val).unwrap(), expected); +#[case('0', Bit::ZERO)] +#[case('1', Bit::ONE)] +fn test_bit_from_char(#[case] val: char, #[case] expected: Bit) { + assert_eq!(Bit::try_from(val).unwrap(), expected); } #[rstest] -#[case(Bit::Zero, '0')] -#[case(Bit::One, '1')] +#[case(Bit::ZERO, '0')] +#[case(Bit::ONE, '1')] fn test_bit_to_char(#[case] bit: Bit, #[case] expected: char) { assert_eq!(>::into(bit), expected); } #[rstest] -#[case(false, Bit::Zero)] -#[case(true, Bit::One)] +#[case(false, Bit::ZERO)] +#[case(true, Bit::ONE)] fn test_bit_from_bool(#[case] val: bool, #[case] expected: Bit) { - assert_eq!(Bit::from(val), expected); + assert_eq!(Bit(val), expected); } #[rstest] -#[case(Bit::Zero, false)] -#[case(Bit::One, true)] +#[case(Bit::ZERO, false)] +#[case(Bit::ONE, true)] fn test_bit_to_bool(#[case] bit: Bit, #[case] expected: bool) { - assert_eq!(>::into(bit), expected); -} - -#[rstest] -#[case(0, Bit::Zero)] -#[case(1, Bit::One)] -fn test_bit_from_int(#[case] val: usize, #[case] expected: Bit) { - assert_eq!(Bit::from_int(val).unwrap(), expected); + assert_eq!(bit.0, expected); } #[test] fn test_bit_not() { - assert_eq!(!Bit::Zero, Bit::One); - assert_eq!(!Bit::One, Bit::Zero); + assert_eq!(!Bit::ZERO, Bit::ONE); + assert_eq!(!Bit::ONE, Bit::ZERO); } #[test] fn test_bit_and() { - assert_eq!(Bit::Zero & Bit::Zero, Bit::Zero); - assert_eq!(Bit::Zero & Bit::One, Bit::Zero); - assert_eq!(Bit::One & Bit::Zero, Bit::Zero); - assert_eq!(Bit::One & Bit::One, Bit::One); + assert_eq!(Bit::ZERO & Bit::ZERO, Bit::ZERO); + assert_eq!(Bit::ZERO & Bit::ONE, Bit::ZERO); + assert_eq!(Bit::ONE & Bit::ZERO, Bit::ZERO); + assert_eq!(Bit::ONE & Bit::ONE, Bit::ONE); } #[test] fn test_bit_or() { - assert_eq!(Bit::Zero | Bit::Zero, Bit::Zero); - assert_eq!(Bit::Zero | Bit::One, Bit::One); - assert_eq!(Bit::One | Bit::Zero, Bit::One); - assert_eq!(Bit::One | Bit::One, Bit::One); + assert_eq!(Bit::ZERO | Bit::ZERO, Bit::ZERO); + assert_eq!(Bit::ZERO | Bit::ONE, Bit::ONE); + assert_eq!(Bit::ONE | Bit::ZERO, Bit::ONE); + assert_eq!(Bit::ONE | Bit::ONE, Bit::ONE); } #[test] fn test_bit_xor() { - assert_eq!(Bit::Zero ^ Bit::Zero, Bit::Zero); - assert_eq!(Bit::Zero ^ Bit::One, Bit::One); - assert_eq!(Bit::One ^ Bit::Zero, Bit::One); - assert_eq!(Bit::One ^ Bit::One, Bit::Zero); + assert_eq!(Bit::ZERO ^ Bit::ZERO, Bit::ZERO); + assert_eq!(Bit::ZERO ^ Bit::ONE, Bit::ONE); + assert_eq!(Bit::ONE ^ Bit::ZERO, Bit::ONE); + assert_eq!(Bit::ONE ^ Bit::ONE, Bit::ZERO); } diff --git a/crates/arbolta/tests/test_bitvec.rs b/crates/arbolta/tests/test_bitvec.rs index 8f51268..132da67 100644 --- a/crates/arbolta/tests/test_bitvec.rs +++ b/crates/arbolta/tests/test_bitvec.rs @@ -1,66 +1,57 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding // SPDX-License-Identifier: MIT use arbolta::bit::{Bit, BitVec}; -use ndarray::{array, Array1}; - +use ndarray::{Array1, array}; use rstest::rstest; #[rstest] // TODO: Generate random bit patterns and check #[case(vec![ - Bit::One, - Bit::Zero, - Bit::One, - Bit::Zero, - Bit::Zero, - Bit::One, - Bit::Zero, - Bit::Zero, + Bit::ONE, + Bit::ZERO, + Bit::ONE, + Bit::ZERO, + Bit::ZERO, + Bit::ONE, + Bit::ZERO, + Bit::ZERO, ], "00100101")] fn test_bits_to_str(#[case] bits: Vec, #[case] expected: String) { - let bits = BitVec { bits: bits }; + let bits: BitVec = bits.into(); assert_eq!(bits.to_string(), expected); } #[rstest] #[case("00100101", vec![ - Bit::One, - Bit::Zero, - Bit::One, - Bit::Zero, - Bit::Zero, - Bit::One, - Bit::Zero, - Bit::Zero, + Bit::ONE, + Bit::ZERO, + Bit::ONE, + Bit::ZERO, + Bit::ZERO, + Bit::ONE, + Bit::ZERO, + Bit::ZERO, ] )] fn test_str_to_bits(#[case] val: String, #[case] expected: Vec) { - assert_eq!(BitVec::try_from(val.as_str()).unwrap().bits, expected) + assert_eq!(BitVec::try_from(val.as_str()).unwrap(), expected.into()) } #[rstest] #[case(vec![ - false, + true, false, true, false, false, true, false, - true, -], vec![ - Bit::One, - Bit::Zero, - Bit::One, - Bit::Zero, - Bit::Zero, - Bit::One, - Bit::Zero, - Bit::Zero, -] + false, +], "00100101" )] -fn test_bools_to_bits(#[case] vals: Vec, #[case] expected: Vec) { - assert_eq!(BitVec::from(vals).bits, expected) +fn test_bools_to_bits(#[case] vals: Vec, #[case] expected: BitVec) { + assert_eq!(BitVec::from_iter(vals), expected) } #[rstest] @@ -236,7 +227,7 @@ fn test_bits_to_i32(#[case] bits: BitVec, #[case] expected: i32) { #[case(182, "10110110")] #[case(171, "10101011")] fn test_u8_to_bits(#[case] val: u8, #[case] expected: BitVec) { - assert_eq!(BitVec::from_int(val).unwrap(), expected) + assert_eq!(BitVec::from_int(val, None), expected) } #[rstest] @@ -253,83 +244,87 @@ fn test_u8_to_bits(#[case] val: u8, #[case] expected: BitVec) { #[case(39090, "1001100010110010")] #[case(36192, "1000110101100000")] fn test_u16_to_bits(#[case] val: u16, #[case] expected: BitVec) { - assert_eq!(BitVec::from_int(val).unwrap(), expected) + assert_eq!(BitVec::from_int(val, None), expected) } // TODO: Test other data types #[rstest] // Reversed element order for bits -#[case(&[124, 70], "0100011001111100")] -#[case(&[253, 43], "0010101111111101")] -#[case(&[114, 74], "0100101001110010")] -#[case(&[179, 61], "0011110110110011")] -#[case(&[27, 184], "1011100000011011")] -#[case(&[190, 97], "0110000110111110")] -#[case(&[205, 117], "0111010111001101")] -#[case(&[255, 111], "0110111111111111")] -#[case(&[253, 176], "1011000011111101")] -#[case(&[220, 231], "1110011111011100")] -fn test_u8_vec_to_bits(#[case] vals: &[u8], #[case] expected: BitVec) { - assert_eq!(BitVec::from_ints(vals).unwrap(), expected); +#[case(vec![124, 70], "0100011001111100")] +#[case(vec![253, 43], "0010101111111101")] +#[case(vec![114, 74], "0100101001110010")] +#[case(vec![179, 61], "0011110110110011")] +#[case(vec![27, 184], "1011100000011011")] +#[case(vec![190, 97], "0110000110111110")] +#[case(vec![205, 117], "0111010111001101")] +#[case(vec![255, 111], "0110111111111111")] +#[case(vec![253, 176], "1011000011111101")] +#[case(vec![220, 231], "1110011111011100")] +fn test_u8_vec_to_bits(#[case] vals: Vec, #[case] expected: BitVec) { + let actual = BitVec::from_ints(vals, None); + assert_eq!(actual.bits, expected.bits); + assert_eq!(actual.shape, [2, 8]); } #[rstest] -#[case(&[0, -114], "1000111000000000")] -#[case(&[-107, 89], "0101100110010101")] -#[case(&[59, -99], "1001110100111011")] -#[case(&[115, -117], "1000101101110011")] -#[case(&[-90, 87], "0101011110100110")] -#[case(&[-80, -49], "1100111110110000")] -#[case(&[-88, 51], "0011001110101000")] -#[case(&[-101, 62], "0011111010011011")] -#[case(&[15, -27], "1110010100001111")] -#[case(&[-58, -95], "1010000111000110")] -fn test_i8_vec_to_bits(#[case] vals: &[i8], #[case] expected: BitVec) { - assert_eq!(BitVec::from_ints(vals).unwrap(), expected); -} - -#[rstest] -#[case(&[30, -44], 7, "10101000011110")] -#[case(&[-19, -42], 7, "10101101101101")] -#[case(&[3, -4], 4, "11000011")] -#[case(&[1, -1], 2, "1101")] -fn test_i8_vec_to_bits_sized( - #[case] vals: &[i8], - #[case] elem_size: usize, +#[case(vec![0, -114], None, "1000111000000000")] +#[case(vec![-107, 89], None, "0101100110010101")] +#[case(vec![59, -99], None, "1001110100111011")] +#[case(vec![115, -117], None, "1000101101110011")] +#[case(vec![-90, 87], None, "0101011110100110")] +#[case(vec![-80, -49], None, "1100111110110000")] +#[case(vec![-88, 51], None, "0011001110101000")] +#[case(vec![-101, 62], None, "0011111010011011")] +#[case(vec![15, -27], None, "1110010100001111")] +#[case(vec![-58, -95], None, "1010000111000110")] +#[case(vec![30, -44], Some(7), "10101000011110")] +#[case(vec![-19, -42], Some(7), "10101101101101")] +#[case(vec![3, -4], Some(4), "11000011")] +#[case(vec![1, -1], Some(2), "1101")] +#[case(vec![1, -1], Some(10), "11111111110000000001")] +fn test_i8_vec_to_bits( + #[case] vals: Vec, + #[case] elem_size: Option, #[case] expected: BitVec, ) { - assert_eq!(BitVec::from_ints_sized(vals, elem_size).unwrap(), expected); + let expected_shape = [vals.len(), elem_size.unwrap_or(i8::BITS as usize)]; + let actual = BitVec::from_ints(vals, elem_size); + assert_eq!(actual.bits, expected.bits); + assert_eq!(actual.shape, expected_shape); } #[rstest] -#[case("0100011001111100", &[124, 70])] -#[case("0010101111111101", &[253, 43])] -#[case("0100101001110010", &[114, 74])] -#[case("0011110110110011", &[179, 61])] -#[case("1011100000011011", &[27, 184])] -#[case("0110000110111110", &[190, 97])] -#[case("0111010111001101", &[205, 117])] -#[case("0110111111111111", &[255, 111])] -#[case("1011000011111101", &[253, 176])] -#[case("1110011111011100", &[220, 231])] -fn test_bits_to_u8_vec(#[case] bits: BitVec, #[case] expected: &[u8]) { - let actual: Vec = bits.to_ints(); +#[case("0100011001111100", vec![124, 70])] +#[case("0010101111111101", vec![253, 43])] +#[case("0100101001110010", vec![114, 74])] +#[case("0011110110110011", vec![179, 61])] +#[case("1011100000011011", vec![27, 184])] +#[case("0110000110111110", vec![190, 97])] +#[case("0111010111001101", vec![205, 117])] +#[case("0110111111111111", vec![255, 111])] +#[case("1011000011111101", vec![253, 176])] +#[case("1110011111011100", vec![220, 231])] +fn test_bits_to_u8_vec(#[case] bits: BitVec, #[case] expected: Vec) { + let actual: Vec = bits.to_ints(Some(u8::BITS as usize)).collect(); assert_eq!(actual, expected); } #[rstest] -#[case("0100011001111100", &[124, 70])] -#[case("0010101111111101", &[253, 43])] -#[case("0100101001110010", &[114, 74])] -#[case("0011110110110011", &[179, 61])] -#[case("1011100000011011", &[27, 184])] -#[case("0110000110111110", &[190, 97])] -#[case("0111010111001101", &[205, 117])] -#[case("0110111111111111", &[255, 111])] -#[case("1011000011111101", &[253, 176])] -#[case("1110011111011100", &[220, 231])] -fn test_bits_to_u8_vec_buffer(#[case] bits: BitVec, #[case] expected: &[u8]) { +#[case("0100011001111100", vec![124, 70])] +#[case("0010101111111101", vec![253, 43])] +#[case("0100101001110010", vec![114, 74])] +#[case("0011110110110011", vec![179, 61])] +#[case("1011100000011011", vec![27, 184])] +#[case("0110000110111110", vec![190, 97])] +#[case("0111010111001101", vec![205, 117])] +#[case("0110111111111111", vec![255, 111])] +#[case("1011000011111101", vec![253, 176])] +#[case("1110011111011100", vec![220, 231])] +fn test_bits_to_u8_vec_buffer(#[case] bits: BitVec, #[case] expected: Vec) { let mut buffer: Vec = vec![0; expected.len()]; - bits.to_ints_buffer(buffer.as_mut_slice()); + bits + .to_ints(Some(u8::BITS as usize)) + .enumerate() + .for_each(|(i, val)| buffer[i] = val); assert_eq!(buffer, expected); } @@ -346,7 +341,8 @@ fn test_bits_to_u8_vec_buffer(#[case] bits: BitVec, #[case] expected: &[u8]) { #[case("1011000011111101", array![253, 176])] #[case("1110011111011100", array![220, 231])] fn test_bits_to_u8_ndarray(#[case] bits: BitVec, #[case] expected: Array1) { - let actual: Array1 = bits.to_int_ndarray(); + let elem_size = bits.shape[1] / expected.len(); + let actual: Array1 = bits.to_ints(Some(elem_size)).collect(); assert_eq!(actual, expected); } @@ -362,22 +358,27 @@ fn test_bits_to_u8_ndarray(#[case] bits: BitVec, #[case] expected: Array1) { #[case("1011000011111101", array![253, 176])] #[case("1110011111011100", array![220, 231])] fn test_bits_to_u8_ndarray_buffer(#[case] bits: BitVec, #[case] expected: Array1) { + let elem_size = bits.shape[1] / expected.len(); let mut buffer: Array1 = Array1::zeros([expected.len()]); - bits.to_int_ndarray_buffer(buffer.view_mut()).unwrap(); + bits + .to_ints(Some(elem_size)) + .zip(buffer.iter_mut()) + .for_each(|(src, dst)| *dst = src); + assert_eq!(buffer, expected); } #[rstest] -#[case("10101000011110", 7, &[30, -44])] -#[case("10101101101101", 7, &[-19, -42])] -#[case("11000011", 4, &[3, -4])] -#[case("1101", 2, &[1, -1])] +#[case("10101000011110", 7, vec![30, -44])] +#[case("10101101101101", 7, vec![-19, -42])] +#[case("11000011", 4, vec![3, -4])] +#[case("1101", 2, vec![1, -1])] fn test_bits_sized_to_i8_vec( #[case] bits: BitVec, #[case] elem_size: usize, - #[case] expected: &[i8], + #[case] expected: Vec, ) { - let actual: Vec = bits.to_ints_sized(elem_size); + let actual: Vec = bits.to_ints(Some(elem_size)).collect(); assert_eq!(actual, expected); } @@ -392,7 +393,11 @@ fn test_bits_sized_to_i8_vec_buffer( #[case] expected: &[i8], ) { let mut buffer: Vec = vec![0; expected.len()]; - bits.to_ints_sized_buffer(elem_size, buffer.as_mut_slice()); + bits + .to_ints(Some(elem_size)) + .zip(buffer.iter_mut()) + .for_each(|(src, dst)| *dst = src); + assert_eq!(buffer, expected); } @@ -408,23 +413,26 @@ fn test_bits_sized_to_i8_ndarray_buffer( ) { let mut buffer: Array1 = Array1::zeros([expected.len()]); bits - .to_int_ndarray_sized_buffer(elem_size, buffer.view_mut()) - .unwrap(); + .to_ints(Some(elem_size)) + .zip(buffer.iter_mut()) + .for_each(|(src, dst)| *dst = src); + assert_eq!(buffer, expected); } #[rstest] -#[case("1000111000000000", &[0, -114])] -#[case("0101100110010101", &[-107, 89])] -#[case("1001110100111011", &[59, -99])] -#[case("1000101101110011", &[115, -117])] -#[case("0101011110100110", &[-90, 87])] -#[case("1100111110110000", &[-80, -49])] -#[case("0011001110101000", &[-88, 51])] -#[case("0011111010011011", &[-101, 62])] -#[case("1110010100001111", &[15, -27])] -#[case("1010000111000110", &[-58, -95])] -fn test_bits_to_i8_vec(#[case] bits: BitVec, #[case] expected: &[i8]) { - let actual: Vec = bits.to_ints(); +#[case("1000111000000000", vec![0, -114])] +#[case("0101100110010101", vec![-107, 89])] +#[case("1001110100111011", vec![59, -99])] +#[case("1000101101110011", vec![115, -117])] +#[case("0101011110100110", vec![-90, 87])] +#[case("1100111110110000", vec![-80, -49])] +#[case("0011001110101000", vec![-88, 51])] +#[case("0011111010011011", vec![-101, 62])] +#[case("1110010100001111", vec![15, -27])] +#[case("1010000111000110", vec![-58, -95])] +fn test_bits_to_i8_vec(#[case] bits: BitVec, #[case] expected: Vec) { + let elem_size = bits.shape[1] / expected.len(); + let actual: Vec = bits.to_ints(Some(elem_size)).collect(); assert_eq!(actual, expected); } diff --git a/crates/arbolta/tests/test_cell.rs b/crates/arbolta/tests/test_cell.rs deleted file mode 100644 index d7cd855..0000000 --- a/crates/arbolta/tests/test_cell.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use arbolta::bit::Bit; -use arbolta::cell::{Cell, Function}; -use arbolta::signal::{AccessSignal, Signal, SignalList}; - -use rstest::rstest; - -#[rstest] -#[case(Function::Inverter, Bit::Zero, Bit::One)] -#[case(Function::Inverter, Bit::One, Bit::Zero)] -#[case(Function::Buf, Bit::Zero, Bit::Zero)] -#[case(Function::Buf, Bit::One, Bit::One)] -fn test_cell_1_input(#[case] function: Function, #[case] a: Bit, #[case] expected: Bit) { - let mut cell = Cell::empty_from_function(function); - let mut signals: SignalList = vec![Signal::new_constant(a), Signal::new_net(1)]; - cell.num_inputs = 1; - cell.input_connections[0] = 0; - cell.output_connection = 1; - - cell.eval(&mut signals); - - let actual = signals[1].get_value(); - assert_eq!(actual, expected); -} - -#[rstest] -#[case(Function::And, Bit::Zero, Bit::Zero, Bit::Zero)] -#[case(Function::And, Bit::Zero, Bit::One, Bit::Zero)] -#[case(Function::And, Bit::One, Bit::Zero, Bit::Zero)] -#[case(Function::And, Bit::One, Bit::One, Bit::One)] -#[case(Function::Nor, Bit::Zero, Bit::Zero, Bit::One)] -#[case(Function::Nor, Bit::Zero, Bit::One, Bit::Zero)] -#[case(Function::Nor, Bit::One, Bit::Zero, Bit::Zero)] -#[case(Function::Nor, Bit::One, Bit::One, Bit::Zero)] -#[case(Function::Nand, Bit::Zero, Bit::Zero, Bit::One)] -#[case(Function::Nand, Bit::Zero, Bit::One, Bit::One)] -#[case(Function::Nand, Bit::One, Bit::Zero, Bit::One)] -#[case(Function::Nand, Bit::One, Bit::One, Bit::Zero)] -#[case(Function::Or, Bit::Zero, Bit::Zero, Bit::Zero)] -#[case(Function::Or, Bit::Zero, Bit::One, Bit::One)] -#[case(Function::Or, Bit::One, Bit::Zero, Bit::One)] -#[case(Function::Or, Bit::One, Bit::One, Bit::One)] -#[case(Function::Xor, Bit::Zero, Bit::Zero, Bit::Zero)] -#[case(Function::Xor, Bit::Zero, Bit::One, Bit::One)] -#[case(Function::Xor, Bit::One, Bit::Zero, Bit::One)] -#[case(Function::Xor, Bit::One, Bit::One, Bit::Zero)] -#[case(Function::Xnor, Bit::Zero, Bit::Zero, Bit::One)] -#[case(Function::Xnor, Bit::Zero, Bit::One, Bit::Zero)] -#[case(Function::Xnor, Bit::One, Bit::Zero, Bit::Zero)] -#[case(Function::Xnor, Bit::One, Bit::One, Bit::One)] -fn test_cell_2_input( - #[case] function: Function, - #[case] a: Bit, - #[case] b: Bit, - #[case] expected: Bit, -) { - let mut cell = Cell::empty_from_function(function); - let mut signals: SignalList = vec![ - Signal::new_constant(a), - Signal::new_constant(b), - Signal::new_net(2), - ]; - - cell.num_inputs = 2; - cell.input_connections[0] = 0; - cell.input_connections[1] = 1; - cell.output_connection = 2; - - cell.eval(&mut signals); - - let actual = signals[2].get_value(); - assert_eq!(actual, expected); -} - -#[rstest] -#[case(Function::Or, Bit::Zero, Bit::Zero, Bit::Zero, Bit::Zero)] -#[case(Function::Or, Bit::Zero, Bit::Zero, Bit::One, Bit::One)] -#[case(Function::Or, Bit::Zero, Bit::One, Bit::Zero, Bit::One)] -#[case(Function::Or, Bit::Zero, Bit::One, Bit::One, Bit::One)] -#[case(Function::Or, Bit::One, Bit::Zero, Bit::Zero, Bit::One)] -#[case(Function::Or, Bit::One, Bit::Zero, Bit::One, Bit::One)] -#[case(Function::Or, Bit::One, Bit::One, Bit::Zero, Bit::One)] -#[case(Function::Or, Bit::One, Bit::One, Bit::One, Bit::One)] -fn test_cell_3_input( - #[case] function: Function, - #[case] a: Bit, - #[case] b: Bit, - #[case] c: Bit, - #[case] expected: Bit, -) { - let mut cell = Cell::empty_from_function(function); - let mut signals: SignalList = vec![ - Signal::new_constant(a), - Signal::new_constant(b), - Signal::new_constant(c), - Signal::new_net(3), - ]; - - cell.num_inputs = 3; - cell.input_connections[0] = 0; - cell.input_connections[1] = 1; - cell.input_connections[2] = 2; - cell.output_connection = 3; - - cell.eval(&mut signals); - - let actual = signals[3].get_value(); - assert_eq!(actual, expected); -} - -#[rstest] -#[case(Function::DffPosEdge, Bit::Zero, Bit::Zero)] -#[case(Function::DffPosEdge, Bit::One, Bit::One)] -fn test_cell_1_input_clocked(#[case] function: Function, #[case] a: Bit, #[case] expected: Bit) { - let mut cell = Cell::empty_from_function(function); - let mut signals: SignalList = vec![ - Signal::new_net(0), - Signal::new_constant(a), - Signal::new_net(2), - ]; - - cell.num_inputs = 2; - cell.input_connections[0] = 0; - cell.input_connections[1] = 1; - cell.output_connection = 2; - - signals[0].set_value(Bit::Zero); - cell.eval(&mut signals); - signals[0].set_value(Bit::One); - cell.eval(&mut signals); - signals[0].set_value(Bit::Zero); - cell.eval(&mut signals); - - let actual = signals[2].get_value(); - assert_eq!(actual, expected); -} - -// TODO: Randomize input testing -// TODO: N-input gate tests diff --git a/crates/arbolta/tests/test_module.rs b/crates/arbolta/tests/test_module.rs deleted file mode 100644 index 1b683a8..0000000 --- a/crates/arbolta/tests/test_module.rs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use arbolta::bit::Bit; -use arbolta::cell::{Cell, Function}; -use arbolta::module::hardware_module::{Component, HardwareModule}; -use arbolta::module::port::{Port, PortDirection}; -use arbolta::signal::Signal; -use once_cell::sync::Lazy; -use rstest::rstest; - -static VARIABLE_ALPHABET: Lazy> = Lazy::new(|| { - (b'a'..=b'z') - .map(|x| String::from_utf8(vec![x]).unwrap()) - .collect() -}); - -fn cell_module_from_function(function: Function, num_inputs: usize) -> HardwareModule { - let mut cell_inputs_connections = [0; 8]; - let mut module = HardwareModule::default(); - - for i in 0..num_inputs { - module.signals.push(Signal::new_net(i)); - module.ports.insert( - VARIABLE_ALPHABET[i].clone(), - Port { - signal_idx_list: vec![i], - shape: [1, 1], - direction: PortDirection::Input, - signed: false, - }, - ); - - cell_inputs_connections[i] = i; - } - module.signals.push(Signal::new_net(num_inputs)); - module.ports.insert( - VARIABLE_ALPHABET[num_inputs].clone(), - Port { - signal_idx_list: vec![num_inputs], - shape: [1, 1], - direction: PortDirection::Output, - signed: false, - }, - ); - - module.components.push(Component::Cell(Cell { - name: String::new(), - function, - state: [Bit::Zero; 2], - input_connections: cell_inputs_connections, - output_connection: num_inputs, - num_inputs, - })); - - module -} - -#[rstest] -#[case(Function::Inverter, 0, 1)] -#[case(Function::Inverter, 1, 0)] -#[case(Function::Buf, 0, 0)] -#[case(Function::Buf, 1, 1)] -fn test_module_1_input_cell(#[case] function: Function, #[case] a: u8, #[case] expected: u8) { - let mut cell_module = cell_module_from_function(function, 1); - cell_module.set_port_int("a", a).unwrap(); - cell_module.eval(); - - let actual: u8 = cell_module.get_port_int("b").unwrap(); - assert_eq!(actual, expected); -} - -#[rstest] -#[case(Function::And, 0, 0, 0)] -#[case(Function::And, 0, 1, 0)] -#[case(Function::And, 1, 0, 0)] -#[case(Function::And, 1, 1, 1)] -#[case(Function::Nor, 0, 0, 1)] -#[case(Function::Nor, 0, 1, 0)] -#[case(Function::Nor, 1, 0, 0)] -#[case(Function::Nor, 1, 1, 0)] -#[case(Function::Nand, 0, 0, 1)] -#[case(Function::Nand, 0, 1, 1)] -#[case(Function::Nand, 1, 0, 1)] -#[case(Function::Nand, 1, 1, 0)] -#[case(Function::Or, 0, 0, 0)] -#[case(Function::Or, 0, 1, 1)] -#[case(Function::Or, 1, 0, 1)] -#[case(Function::Or, 1, 1, 1)] -#[case(Function::Xor, 0, 0, 0)] -#[case(Function::Xor, 0, 1, 1)] -#[case(Function::Xor, 1, 0, 1)] -#[case(Function::Xor, 1, 1, 0)] -#[case(Function::Xnor, 0, 0, 1)] -#[case(Function::Xnor, 0, 1, 0)] -#[case(Function::Xnor, 1, 0, 0)] -#[case(Function::Xnor, 1, 1, 1)] -fn test_module_2_input_cell( - #[case] function: Function, - #[case] a: u8, - #[case] b: u8, - #[case] expected: u8, -) { - let mut cell_module = cell_module_from_function(function, 2); - cell_module.set_port_int("a", a).unwrap(); - cell_module.set_port_int("b", b).unwrap(); - cell_module.eval(); - - let actual: u8 = cell_module.get_port_int("c").unwrap(); - assert_eq!(actual, expected); -} - -#[rstest] -#[case(Function::Or, 0, 0, 0, 0)] -#[case(Function::Or, 0, 0, 1, 1)] -#[case(Function::Or, 0, 1, 0, 1)] -#[case(Function::Or, 0, 1, 1, 1)] -#[case(Function::Or, 1, 0, 0, 1)] -#[case(Function::Or, 1, 0, 1, 1)] -#[case(Function::Or, 1, 1, 0, 1)] -#[case(Function::Or, 1, 1, 1, 1)] -fn test_module_3_input_cell( - #[case] function: Function, - #[case] a: u8, - #[case] b: u8, - #[case] c: u8, - #[case] expected: u8, -) { - let mut cell_module = cell_module_from_function(function, 3); - cell_module.set_port_int("a", a).unwrap(); - cell_module.set_port_int("b", b).unwrap(); - cell_module.set_port_int("c", c).unwrap(); - cell_module.eval(); - - let actual: u8 = cell_module.get_port_int("d").unwrap(); - assert_eq!(actual, expected); -} - -#[rstest] -#[case(Function::DffPosEdge, 0, 0)] -#[case(Function::DffPosEdge, 1, 1)] -fn test_module_1_input_cell_clocked( - #[case] function: Function, - #[case] a: u8, - #[case] expected: u8, -) { - let mut cell_module = cell_module_from_function(function, 2); - - cell_module.set_port_int("a", 0).unwrap(); // clock - cell_module.set_port_int("b", a).unwrap(); - cell_module.eval(); - - cell_module.set_port_int("a", 1).unwrap(); - cell_module.eval(); - - cell_module.set_port_int("a", 0).unwrap(); - cell_module.eval(); - - let actual: u8 = cell_module.get_port_int("c").unwrap(); - assert_eq!(actual, expected); -} diff --git a/crates/arbolta/tests/test_netlists/4b_adder_netlist.json b/crates/arbolta/tests/test_netlists/4b_adder_netlist.json deleted file mode 100644 index a10acb5..0000000 --- a/crates/arbolta/tests/test_netlists/4b_adder_netlist.json +++ /dev/null @@ -1,133 +0,0 @@ -{ - "modules": { - "adder": { - "ports": { - "op0_i": {"direction": "input", "bits": [ 2, 3, 4, 5 ]}, - "op1_i": {"direction": "input", "bits": [ 6, 7, 8, 9 ]}, - "sum_o": {"direction": "output", "bits": [ 10, 11, 12, 13, 14 ]} - }, - "cells": { - "$202": {"type": "NOT", "connections": {"A": [ 3 ], "Y": [ 15 ]}}, - "$203": {"type": "NOT", "connections": {"A": [ 7 ], "Y": [ 16 ]}}, - "$204": {"type": "NOT", "connections": {"A": [ 2 ], "Y": [ 17 ]}}, - "$205": {"type": "NOT", "connections": {"A": [ 6 ], "Y": [ 18 ]}}, - "$206": {"type": "NOT", "connections": {"A": [ 4 ], "Y": [ 19 ]}}, - "$207": {"type": "NOT", "connections": {"A": [ 8 ], "Y": [ 20 ]}}, - "$208": {"type": "NOT", "connections": {"A": [ 5 ], "Y": [ 21 ]}}, - "$209": {"type": "NOT", "connections": {"A": [ 9 ], "Y": [ 22 ]}}, - "$210": {"type": "NOR", "connections": {"A": [ 17 ], "B": [ 18 ], "Y": [ 23 ]}}, - "$211": {"type": "NAND", "connections": {"A": [ 2 ], "B": [ 6 ], "Y": [ 24 ]}}, - "$212": {"type": "NOR", "connections": {"A": [ 15 ], "B": [ 16 ], "Y": [ 25 ]}}, - "$213": {"type": "NAND", "connections": {"A": [ 3 ], "B": [ 7 ], "Y": [ 26 ]}}, - "$214": {"type": "NOR", "connections": {"A": [ 3 ], "B": [ 7 ], "Y": [ 27 ]}}, - "$215": {"type": "NOT", "connections": {"A": [ 27 ], "Y": [ 28 ]}}, - "$216": {"type": "NOR", "connections": {"A": [ 25 ], "B": [ 27 ], "Y": [ 29 ]}}, - "$217": {"type": "NAND", "connections": {"A": [ 26 ], "B": [ 28 ], "Y": [ 30 ]}}, - "$218": {"type": "NOR", "connections": {"A": [ 24 ], "B": [ 30 ], "Y": [ 31 ]}}, - "$219": {"type": "NAND", "connections": {"A": [ 23 ], "B": [ 29 ], "Y": [ 32 ]}}, - "$220": {"type": "NOR", "connections": {"A": [ 23 ], "B": [ 29 ], "Y": [ 33 ]}}, - "$221": {"type": "NOR", "connections": {"A": [ 31 ], "B": [ 33 ], "Y": [ 11 ]}}, - "$222": {"type": "NOR", "connections": {"A": [ 25 ], "B": [ 31 ], "Y": [ 34 ]}}, - "$223": {"type": "NAND", "connections": {"A": [ 26 ], "B": [ 32 ], "Y": [ 35 ]}}, - "$224": {"type": "NOR", "connections": {"A": [ 19 ], "B": [ 20 ], "Y": [ 36 ]}}, - "$225": {"type": "NAND", "connections": {"A": [ 4 ], "B": [ 8 ], "Y": [ 37 ]}}, - "$226": {"type": "NOR", "connections": {"A": [ 4 ], "B": [ 8 ], "Y": [ 38 ]}}, - "$227": {"type": "NOR", "connections": {"A": [ 36 ], "B": [ 38 ], "Y": [ 39 ]}}, - "$228": {"type": "NOT", "connections": {"A": [ 39 ], "Y": [ 40 ]}}, - "$229": {"type": "NOR", "connections": {"A": [ 34 ], "B": [ 40 ], "Y": [ 41 ]}}, - "$230": {"type": "NAND", "connections": {"A": [ 35 ], "B": [ 39 ], "Y": [ 42 ]}}, - "$231": {"type": "NOR", "connections": {"A": [ 35 ], "B": [ 39 ], "Y": [ 43 ]}}, - "$232": {"type": "NOR", "connections": {"A": [ 41 ], "B": [ 43 ], "Y": [ 12 ]}}, - "$233": {"type": "NOR", "connections": {"A": [ 36 ], "B": [ 41 ], "Y": [ 44 ]}}, - "$234": {"type": "NAND", "connections": {"A": [ 37 ], "B": [ 42 ], "Y": [ 45 ]}}, - "$235": {"type": "NAND", "connections": {"A": [ 5 ], "B": [ 9 ], "Y": [ 46 ]}}, - "$236": {"type": "NOT", "connections": {"A": [ 46 ], "Y": [ 47 ]}}, - "$237": {"type": "NOR", "connections": {"A": [ 5 ], "B": [ 9 ], "Y": [ 48 ]}}, - "$238": {"type": "NAND", "connections": {"A": [ 21 ], "B": [ 22 ], "Y": [ 49 ]}}, - "$239": {"type": "NOR", "connections": {"A": [ 47 ], "B": [ 48 ], "Y": [ 50 ]}}, - "$240": {"type": "NAND", "connections": {"A": [ 46 ], "B": [ 49 ], "Y": [ 51 ]}}, - "$241": {"type": "NAND", "connections": {"A": [ 44 ], "B": [ 50 ], "Y": [ 52 ]}}, - "$242": {"type": "NAND", "connections": {"A": [ 45 ], "B": [ 51 ], "Y": [ 53 ]}}, - "$243": {"type": "NAND", "connections": {"A": [ 52 ], "B": [ 53 ], "Y": [ 13 ]}}, - "$244": {"type": "NOR", "connections": {"A": [ 2 ], "B": [ 6 ], "Y": [ 54 ]}}, - "$245": {"type": "NOR", "connections": {"A": [ 23 ], "B": [ 54 ], "Y": [ 10 ]}}, - "$246": {"type": "NAND", "connections": {"A": [ 45 ], "B": [ 49 ], "Y": [ 55 ]}}, - "$247": {"type": "NAND", "connections": {"A": [ 46 ], "B": [ 55 ], "Y": [ 14 ]}} - }, - "netnames": { - "$180$new_n14": {"bits": [ 56 ]}, - "$180$new_n15": {"bits": [ 57 ]}, - "$180$new_n17": {"bits": [ 58 ]}, - "$180$new_n18": {"bits": [ 59 ]}, - "$180$new_n19": {"bits": [ 60 ]}, - "$180$new_n20": {"bits": [ 61 ]}, - "$180$new_n22": {"bits": [ 62 ]}, - "$180$new_n23": {"bits": [ 63 ]}, - "$180$new_n24": {"bits": [ 64 ]}, - "$180$new_n25": {"bits": [ 65 ]}, - "$180$new_n28": {"bits": [ 66 ]}, - "$180$new_n29": {"bits": [ 67 ]}, - "$180$new_n30": {"bits": [ 68 ]}, - "$180$new_n31": {"bits": [ 69 ]}, - "$180$new_n32": {"bits": [ 70 ]}, - "$201$new_n14": {"bits": [ 15 ]}, - "$201$new_n15": {"bits": [ 16 ]}, - "$201$new_n16": {"bits": [ 17 ]}, - "$201$new_n17": {"bits": [ 18 ]}, - "$201$new_n18": {"bits": [ 19 ]}, - "$201$new_n19": {"bits": [ 20 ]}, - "$201$new_n20": {"bits": [ 21 ]}, - "$201$new_n21": {"bits": [ 22 ]}, - "$201$new_n22": {"bits": [ 23 ]}, - "$201$new_n23": {"bits": [ 24 ]}, - "$201$new_n24": {"bits": [ 25 ]}, - "$201$new_n25": {"bits": [ 26 ]}, - "$201$new_n26": {"bits": [ 27 ]}, - "$201$new_n27": {"bits": [ 28 ]}, - "$201$new_n28": {"bits": [ 29 ]}, - "$201$new_n29": {"bits": [ 30 ]}, - "$201$new_n30": {"bits": [ 31 ]}, - "$201$new_n31": {"bits": [ 32 ]}, - "$201$new_n32": {"bits": [ 33 ]}, - "$201$new_n34": {"bits": [ 34 ]}, - "$201$new_n35": {"bits": [ 35 ]}, - "$201$new_n36": {"bits": [ 36 ]}, - "$201$new_n37": {"bits": [ 37 ]}, - "$201$new_n38": {"bits": [ 38 ]}, - "$201$new_n39": {"bits": [ 39 ]}, - "$201$new_n40": {"bits": [ 40 ]}, - "$201$new_n41": {"bits": [ 41 ]}, - "$201$new_n42": {"bits": [ 42 ]}, - "$201$new_n43": {"bits": [ 43 ]}, - "$201$new_n45": {"bits": [ 44 ]}, - "$201$new_n46": {"bits": [ 45 ]}, - "$201$new_n47": {"bits": [ 46 ]}, - "$201$new_n48": {"bits": [ 47 ]}, - "$201$new_n49": {"bits": [ 48 ]}, - "$201$new_n50": {"bits": [ 49 ]}, - "$201$new_n51": {"bits": [ 50 ]}, - "$201$new_n52": {"bits": [ 51 ]}, - "$201$new_n53": {"bits": [ 52 ]}, - "$201$new_n54": {"bits": [ 53 ]}, - "$201$new_n56": {"bits": [ 54 ]}, - "$201$new_n58": {"bits": [ 55 ]}, - "$201$op0_i[0]": {"bits": [ 2 ]}, - "$201$op0_i[1]": {"bits": [ 3 ]}, - "$201$op0_i[2]": {"bits": [ 4 ]}, - "$201$op0_i[3]": {"bits": [ 5 ]}, - "$201$op1_i[0]": {"bits": [ 6 ]}, - "$201$op1_i[1]": {"bits": [ 7 ]}, - "$201$op1_i[2]": {"bits": [ 8 ]}, - "$201$op1_i[3]": {"bits": [ 9 ]}, - "$201$sum_o[0]": {"bits": [ 10 ]}, - "$201$sum_o[1]": {"bits": [ 11 ]}, - "$201$sum_o[2]": {"bits": [ 12 ]}, - "$201$sum_o[3]": {"bits": [ 13 ]}, - "$201$sum_o[4]": {"bits": [ 14 ]}, - "op0_i": {"bits": [ 2, 3, 4, 5 ]}, - "op1_i": {"bits": [ 6, 7, 8, 9 ]}, - "sum_o": {"bits": [ 10, 11, 12, 13, 14 ]} - } - } - } -} diff --git a/crates/arbolta/tests/test_netlists/4b_nested_adder_netlist.json b/crates/arbolta/tests/test_netlists/4b_nested_adder_netlist.json deleted file mode 100644 index 16f3527..0000000 --- a/crates/arbolta/tests/test_netlists/4b_nested_adder_netlist.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "modules": { - "adder": { - "ports": { - "op0_i": {"direction": "input", "bits": [ 2, 3, 4, 5 ]}, - "op1_i": {"direction": "input", "bits": [ 6, 7, 8, 9 ]}, - "sum_o": {"direction": "output","bits": [ 10, 11, 12, 13, 14 ]} - }, - "cells": { - "fa0": { - "type": "full_adder", - "port_directions": {"carry_i": "input", "carry_o": "output", "op0_i": "input", "op1_i": "input", "sum_o": "output"}, - "connections": {"carry_i": [ "0" ], "carry_o": [ 15 ], "op0_i": [ 2 ], "op1_i": [ 6 ], "sum_o": [ 10 ]} - }, - "fa1": { - "type": "full_adder", - "port_directions": {"carry_i": "input", "carry_o": "output", "op0_i": "input", "op1_i": "input", "sum_o": "output"}, - "connections": {"carry_i": [ 15 ], "carry_o": [ 16 ], "op0_i": [ 3 ], "op1_i": [ 7 ], "sum_o": [ 11 ]} - }, - "fa2": { - "type": "full_adder", - "port_directions": {"carry_i": "input", "carry_o": "output", "op0_i": "input", "op1_i": "input", "sum_o": "output"}, - "connections": {"carry_i": [ 16 ], "carry_o": [ 17 ], "op0_i": [ 4 ], "op1_i": [ 8 ], "sum_o": [ 12 ]} - }, - "fa3": { - "type": "full_adder", - "port_directions": {"carry_i": "input", "carry_o": "output", "op0_i": "input", "op1_i": "input", "sum_o": "output"}, - "connections": {"carry_i": [ 17 ], "carry_o": [ 14 ], "op0_i": [ 5 ], "op1_i": [ 9 ], "sum_o": [ 13 ]} - } - }, - "netnames": { - "fa0_carry": {"bits": [ 15 ]}, - "fa1_carry": {"bits": [ 16 ]}, - "fa2_carry": {"bits": [ 17 ]}, - "op0_i": {"bits": [ 2, 3, 4, 5 ]}, - "op1_i": {"bits": [ 6, 7, 8, 9 ]}, - "sum_o": {"bits": [ 10, 11, 12, 13, 14 ]} - } - }, - "full_adder": { - "ports": { - "carry_i": {"direction": "input", "bits": [ 2 ]}, - "op0_i": {"direction": "input", "bits": [ 3 ]}, - "op1_i": {"direction": "input", "bits": [ 4 ]}, - "sum_o": {"direction": "output", "bits": [ 5 ]}, - "carry_o": {"direction": "output", "bits": [ 6 ]} - }, - "cells": { - "$154": {"type": "NOT", "connections": {"A": [ 4 ], "Y": [ 7 ]}}, - "$155": {"type": "NOR", "connections": {"A": [ 2 ], "B": [ 3 ], "Y": [ 8 ]}}, - "$156": {"type": "NOT", "connections": {"A": [ 8 ], "Y": [ 9 ]}}, - "$157": {"type": "NAND", "connections": {"A": [ 2 ], "B": [ 3 ], "Y": [ 10 ]}}, - "$158": {"type": "NOT", "connections": {"A": [ 10 ], "Y": [ 11 ]}}, - "$159": {"type": "NOR", "connections": {"A": [ 8 ], "B": [ 11 ], "Y": [ 12 ]}}, - "$160": {"type": "NAND", "connections": {"A": [ 9 ], "B": [ 10 ], "Y": [ 13 ]}}, - "$161": {"type": "NOR", "connections": {"A": [ 7 ], "B": [ 13 ], "Y": [ 14 ]}}, - "$162": {"type": "NAND", "connections": {"A": [ 4 ], "B": [ 12 ], "Y": [ 15 ]}}, - "$163": {"type": "NOR", "connections": {"A": [ 4 ], "B": [ 12 ], "Y": [ 16 ]}}, - "$164": {"type": "NOR", "connections": {"A": [ 14 ], "B": [ 16 ], "Y": [ 5 ]}}, - "$165": {"type": "NAND", "connections": {"A": [ 10 ], "B": [ 15 ], "Y": [ 6 ]}} - }, - "netnames": { - "$146$new_n6": {"bits": [ 17 ]}, - "$146$new_n8": {"bits": [ 18 ]}, - "$146$new_n9": {"bits": [ 19 ]}, - "$153$carry_i": {"bits": [ 2 ]}, - "$153$carry_o": {"bits": [ 6 ]}, - "$153$new_n10": {"bits": [ 11 ]}, - "$153$new_n11": {"bits": [ 12 ]}, - "$153$new_n12": {"bits": [ 13 ]}, - "$153$new_n13": {"bits": [ 14 ]}, - "$153$new_n14": {"bits": [ 15 ]}, - "$153$new_n15": {"bits": [ 16 ]}, - "$153$new_n6": {"bits": [ 7 ]}, - "$153$new_n7": {"bits": [ 8 ]}, - "$153$new_n8": {"bits": [ 9 ]}, - "$153$new_n9": {"bits": [ 10 ]}, - "$153$op0_i": {"bits": [ 3 ]}, - "$153$op1_i": {"bits": [ 4 ]}, - "$153$sum_o": {"bits": [ 5 ]}, - "carry_i": {"bits": [ 2 ]}, - "carry_o": {"bits": [ 6 ]}, - "op0_i": {"bits": [ 3 ]}, - "op1_i": {"bits": [ 4 ]}, - "sum_o": {"bits": [ 5 ]} - } - } - } - } diff --git a/crates/arbolta/tests/test_signal.rs b/crates/arbolta/tests/test_signal.rs index 4f149e0..2579b58 100644 --- a/crates/arbolta/tests/test_signal.rs +++ b/crates/arbolta/tests/test_signal.rs @@ -1,85 +1,87 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding // SPDX-License-Identifier: MIT use arbolta::bit::Bit; -use arbolta::signal::{AccessSignal, Signal}; +use arbolta::signal::Signals; #[test] fn test_signal_net_init() { - let x = Signal::new_net(0); + let x = Signals::new(1); - assert_eq!(x.get_value(), Bit::Zero); - assert_eq!(x.get_toggle_count_falling(), 0); - assert_eq!(x.get_toggle_count_rising(), 0); - assert_eq!(x.get_total_toggle_count(), 0); - assert_eq!(x.get_index(), 0); + assert_eq!(x.get_net(0), Bit::ZERO); + assert_eq!(x.get_toggles_falling(0), 0); + assert_eq!(x.get_toggles_rising(0), 0); + assert_eq!(x.get_toggles_total(0), 0); } #[test] fn test_signal_net_set_value() { - let mut x = Signal::new_net(0); + let mut x = Signals::new(1); - assert_eq!(x.get_value(), Bit::Zero); - x.set_value(Bit::One); - assert_eq!(x.get_value(), Bit::One); + assert_eq!(x.get_net(0), Bit::ZERO); + x.set_net(0, Bit::ONE); + assert_eq!(x.get_net(0), Bit::ONE); } #[test] fn test_signal_net_toggle_rising() { - let mut x = Signal::new_net(0); + let mut x = Signals::new(1); - assert_eq!(x.get_total_toggle_count(), 0); - assert_eq!(x.get_toggle_count_falling(), 0); - assert_eq!(x.get_toggle_count_rising(), 0); + assert_eq!(x.get_toggles_total(0), 0); + assert_eq!(x.get_toggles_falling(0), 0); + assert_eq!(x.get_toggles_rising(0), 0); - x.set_value(Bit::One); + x.set_net(0, Bit::ONE); - assert_eq!(x.get_total_toggle_count(), 1); - assert_eq!(x.get_toggle_count_falling(), 0); - assert_eq!(x.get_toggle_count_rising(), 1); + assert_eq!(x.get_toggles_total(0), 1); + assert_eq!(x.get_toggles_falling(0), 0); + assert_eq!(x.get_toggles_rising(0), 1); } #[test] fn test_signal_net_toggle_falling() { - let mut x = Signal::new_net_from(0, Bit::One); + let mut x = Signals::new(1); + x.nets[0] = Bit::ONE; - assert_eq!(x.get_total_toggle_count(), 0); - assert_eq!(x.get_toggle_count_falling(), 0); - assert_eq!(x.get_toggle_count_rising(), 0); + assert_eq!(x.get_toggles_total(0), 0); + assert_eq!(x.get_toggles_falling(0), 0); + assert_eq!(x.get_toggles_rising(0), 0); - x.set_value(Bit::Zero); + x.set_net(0, Bit::ZERO); - assert_eq!(x.get_total_toggle_count(), 1); - assert_eq!(x.get_toggle_count_falling(), 1); - assert_eq!(x.get_toggle_count_rising(), 0); + assert_eq!(x.get_toggles_total(0), 1); + assert_eq!(x.get_toggles_falling(0), 1); + assert_eq!(x.get_toggles_rising(0), 0); } #[test] fn test_signal_net_toggle_same_zero() { - let mut x = Signal::new_net(0); + let mut x = Signals::new(1); - assert_eq!(x.get_total_toggle_count(), 0); - assert_eq!(x.get_toggle_count_falling(), 0); - assert_eq!(x.get_toggle_count_rising(), 0); + assert_eq!(x.get_toggles_total(0), 0); + assert_eq!(x.get_toggles_falling(0), 0); + assert_eq!(x.get_toggles_rising(0), 0); - x.set_value(Bit::Zero); + x.set_net(0, Bit::ZERO); - assert_eq!(x.get_total_toggle_count(), 0); - assert_eq!(x.get_toggle_count_falling(), 0); - assert_eq!(x.get_toggle_count_rising(), 0); + assert_eq!(x.get_toggles_total(0), 0); + assert_eq!(x.get_toggles_falling(0), 0); + assert_eq!(x.get_toggles_rising(0), 0); } #[test] fn test_signal_net_toggle_same_one() { - let mut x = Signal::new_net_from(0, Bit::One); + let mut x = Signals::new(1); + x.nets[0] = Bit::ONE; - assert_eq!(x.get_total_toggle_count(), 0); - assert_eq!(x.get_toggle_count_falling(), 0); - assert_eq!(x.get_toggle_count_rising(), 0); + assert_eq!(x.get_toggles_total(0), 0); + assert_eq!(x.get_toggles_falling(0), 0); + assert_eq!(x.get_toggles_rising(0), 0); - x.set_value(Bit::One); + x.set_net(0, Bit::ONE); - assert_eq!(x.get_total_toggle_count(), 0); - assert_eq!(x.get_toggle_count_falling(), 0); - assert_eq!(x.get_toggle_count_rising(), 0); + assert_eq!(x.get_toggles_total(0), 0); + assert_eq!(x.get_toggles_falling(0), 0); + assert_eq!(x.get_toggles_rising(0), 0); } diff --git a/crates/arbolta/tests/test_simcell.rs b/crates/arbolta/tests/test_simcell.rs new file mode 100644 index 0000000..8b18bcf --- /dev/null +++ b/crates/arbolta/tests/test_simcell.rs @@ -0,0 +1,271 @@ +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use arbolta::bit::Bit; +use arbolta::cell::*; +use arbolta::signal::Signals; +use rstest::rstest; + +fn convert_bits(x: [u8; T]) -> [Bit; T] { + let mut converted = [Bit::ZERO; T]; + for i in 0..T { + converted[i] = Bit::from_int(x[i]).unwrap(); + } + converted +} + +#[rstest] +#[case::buffer(Box::new(Buffer::new(0,1)), [ // (A, Y) + (0, 0), + (1, 1), +])] +#[case::inverter(Box::new(Inverter::new(0,1)), [ // (A, Y) + (0, 1), + (1, 0), +])] +fn test_cell_unary(#[case] mut cell: Box, #[case] cases: [(u8, u8); 2]) { + let mut signals = Signals::new(2); + for (a, expected) in cases { + let [a, expected] = convert_bits([a, expected]); + + signals.set_net(0, a); + cell.eval(&mut signals); + assert_eq!(signals.get_net(1), expected, "input `{a}`") + } +} + +#[rstest] +#[case::and(Box::new(And2::new(0, 1, 2)), [ // (A, B, Y) + (0, 0, 0), + (0, 1, 0), + (1, 0, 0), + (1, 1, 1), +])] +#[case::andnot(Box::new(AndNot2::new(0, 1, 2)), [ // (A, B, Y) + (0, 0, 0), + (0, 1, 0), + (1, 0, 1), + (1, 1, 0), +])] +#[case::nand(Box::new(Nand2::new(0, 1, 2)), [ // (A, B, Y) + (0, 0, 1), + (0, 1, 1), + (1, 0, 1), + (1, 1, 0), +])] +#[case::nor(Box::new(Nor2::new(0, 1, 2)), [ // (A, B, Y) + (0, 0, 1), + (0, 1, 0), + (1, 0, 0), + (1, 1, 0), +])] +#[case::or(Box::new(Or2::new(0, 1, 2)), [ // (A, B, Y) + (0, 0, 0), + (0, 1, 1), + (1, 0, 1), + (1, 1, 1), +])] +#[case::ornot(Box::new(OrNot2::new(0, 1, 2)), [ // (A, B, Y) + (0, 0, 1), + (0, 1, 0), + (1, 0, 1), + (1, 1, 1), +])] +#[case::xnor(Box::new(Xnor2::new(0, 1, 2)), [ // (A, B, Y) + (0, 0, 1), + (0, 1, 0), + (1, 0, 0), + (1, 1, 1), +])] +#[case::xor(Box::new(Xor2::new(0, 1, 2)), [ // (A, B, Y) + (0, 0, 0), + (0, 1, 1), + (1, 0, 1), + (1, 1, 0), +])] +fn test_cell_binary(#[case] mut cell: Box, #[case] cases: [(u8, u8, u8); 4]) { + let mut signals = Signals::new(3); + for (a, b, expected) in cases { + let [a, b, expected] = convert_bits([a, b, expected]); + + signals.set_net(0, a); + signals.set_net(1, b); + + cell.eval(&mut signals); + assert_eq!(signals.get_net(2), expected, "inputs `{a}`, `{b}`") + } +} + +#[rstest] +#[case::andorinvert(Box::new(AndOrInvert3::new(0, 1, 2, 3)), [ // (A, B, C, Y) + (0, 0, 0, 1), + (0, 0, 1, 0), + (0, 1, 0, 1), + (0, 1, 1, 0), + (1, 0, 0, 1), + (1, 0, 1, 0), + (1, 1, 0, 0), + (1, 1, 1, 0), +])] +#[case::mux2(Box::new(Mux2::new(0, 1, 2, 3)), [ // (A, B, S, Y) + (0, 0, 0, 0), + (0, 0, 1, 0), + (0, 1, 0, 0), + (0, 1, 1, 1), + (1, 0, 0, 1), + (1, 0, 1, 0), + (1, 1, 0, 1), + (1, 1, 1, 1), +])] +#[case::nmux2(Box::new(NMux2::new(0, 1, 2, 3)), [ // (A, B, S, Y) + (0, 0, 0, 1), + (0, 0, 1, 1), + (0, 1, 0, 1), + (0, 1, 1, 0), + (1, 0, 0, 0), + (1, 0, 1, 1), + (1, 1, 0, 0), + (1, 1, 1, 0), +])] +#[case::orandinvert(Box::new(OrAndInvert3::new(0, 1, 2, 3)), [ // (A, B, C, Y) + (0, 0, 0, 1), + (0, 0, 1, 1), + (0, 1, 0, 1), + (0, 1, 1, 0), + (1, 0, 0, 1), + (1, 0, 1, 0), + (1, 1, 0, 1), + (1, 1, 1, 0), +])] +fn test_cell_ternary(#[case] mut cell: Box, #[case] cases: [(u8, u8, u8, u8); 8]) { + let mut signals = Signals::new(4); + for (a, b, c, expected) in cases { + let [a, b, c, expected] = convert_bits([a, b, c, expected]); + + signals.set_net(0, a); + signals.set_net(1, b); + signals.set_net(2, c); + cell.eval(&mut signals); + assert_eq!(signals.get_net(3), expected, "inputs `{a}`, `{b}`, `{c}`") + } +} + +#[rstest] +#[case::half_adder_inv(Box::new(Asap7HalfAdderInv::new(0, 1, 2, 3)), [ // A, B, SO, CO + (0, 0, 1, 1), + (0, 1, 0, 1), + (1, 0, 0, 1), + (1, 1, 1, 0), +])] +fn test_cell_binary_two_output( + #[case] mut cell: Box, + #[case] cases: [(u8, u8, u8, u8); 4], +) { + let mut signals = Signals::new(4); + for (a, b, exp_x, exp_y) in cases { + let [a, b, exp_x, exp_y] = convert_bits([a, b, exp_x, exp_y]); + + signals.set_net(0, a); + signals.set_net(1, b); + cell.eval(&mut signals); + assert_eq!(signals.get_net(2), exp_x, "inputs `{a}`, `{b}`"); + assert_eq!(signals.get_net(3), exp_y, "inputs `{a}`, `{b}`"); + } +} + +#[rstest] +#[case::full_adder_inv(Box::new(Asap7FullAdderInv::new(0, 1, 2, 3, 4)), [ // A, B, CI, SO, CO + (0, 0, 0, 1, 1), + (0, 0, 1, 0, 1), + (0, 1, 0, 0, 1), + (0, 1, 1, 1, 0), + (1, 0, 0, 0, 1), + (1, 0, 1, 1, 0), + (1, 1, 0, 1, 0), + (1, 1, 1, 0, 0), +])] +fn test_cell_ternary_two_output( + #[case] mut cell: Box, + #[case] cases: [(u8, u8, u8, u8, u8); 8], +) { + let mut signals = Signals::new(5); + for (a, b, c, exp_x, exp_y) in cases { + let [a, b, c, exp_x, exp_y] = convert_bits([a, b, c, exp_x, exp_y]); + + signals.set_net(0, a); + signals.set_net(1, b); + signals.set_net(2, c); + cell.eval(&mut signals); + assert_eq!(signals.get_net(3), exp_x, "inputs `{a}, {b}, {c}`"); + assert_eq!(signals.get_net(4), exp_y, "inputs `{a}, {b}, {c}`"); + } +} + +#[rstest] +fn test_cell_dff_posedge() { + let (clock, data_in, data_out) = (0, 1, 2); + let mut cell = Dff::new(Bit::ONE, clock, data_in, data_out); + let mut signals = Signals::new(3); + + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ZERO); + + signals.set_net(data_in, Bit::ONE); + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ZERO); + + signals.set_net(clock, Bit::ONE); // Rising edge + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ONE); + + signals.set_net(clock, Bit::ZERO); // Falling edge + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ONE); + + signals.set_net(data_in, Bit::ZERO); + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ONE); + + signals.set_net(clock, Bit::ONE); // Rising edge + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ZERO); +} + +#[rstest] +fn test_cell_sdff_pp() { + let (clock, reset, data_in, data_out) = (0, 1, 2, 3); + let mut cell = DffReset::new( + Bit::ONE, + Bit::ONE, + Bit::ZERO, + clock, + reset, + data_in, + data_out, + ); + let mut signals = Signals::new(4); + + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ZERO); + + signals.set_net(data_in, Bit::ONE); + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ZERO); + + signals.set_net(clock, Bit::ONE); // Rising edge + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ONE); + + signals.set_net(clock, Bit::ZERO); // Falling edge + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ONE); + + signals.set_net(reset, Bit::ONE); + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ONE); + + signals.set_net(clock, Bit::ONE); // Rising edge + cell.eval(&mut signals); + assert_eq!(signals.get_net(data_out), Bit::ZERO); +} diff --git a/crates/arbolta/tests/test_simcell_module.rs b/crates/arbolta/tests/test_simcell_module.rs new file mode 100644 index 0000000..bcda44e --- /dev/null +++ b/crates/arbolta/tests/test_simcell_module.rs @@ -0,0 +1,168 @@ +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use arbolta::{bit::BitVec, hardware_module::HardwareModule}; +use once_cell::sync::Lazy; +use rstest::rstest; +use std::collections::HashMap; +use yosys_netlist_json::Netlist; + +static CELL_WRAPPER_NETLIST: Lazy = + Lazy::new(|| Netlist::from_slice(include_bytes!("deps/simcells_wrappers.json")).unwrap()); + +#[rstest] +#[case::buffer("$_BUF__WRAPPER", [ + (0, 0), + (1, 1), +])] +#[case::inverter("$_NOT__WRAPPER", [ + (0, 1), + (1, 0), +])] +fn test_module_unary_cell(#[case] cell: &str, #[case] cases: [(u8, u8); 2]) { + let cell_type = cell.strip_suffix("_WRAPPER").unwrap(); + let torder = HashMap::from([(cell, vec![cell_type])]); + let mut module = + HardwareModule::new(CELL_WRAPPER_NETLIST.clone(), Some(cell), torder, None, None).unwrap(); + + for (a, expected) in cases { + module.set_port("A", BitVec::from_int(a, None)).unwrap(); + module.eval(); + let actual: u8 = module.get_port("Y").unwrap().to_int(); + assert_eq!(actual, expected, "input: `{a}`"); + } +} + +#[rstest] +#[case("$_AND__WRAPPER", [ + (0, 0, 0), + (0, 1, 0), + (1, 0, 0), + (1, 1, 1), +])] +#[case("$_ANDNOT__WRAPPER", [ + (0, 0, 0), + (0, 1, 0), + (1, 0, 1), + (1, 1, 0), +])] +#[case("$_NOR__WRAPPER", [ + (0, 0, 1), + (0, 1, 0), + (1, 0, 0), + (1, 1, 0), +])] +#[case("$_NAND__WRAPPER", [ + (0, 0, 1), + (0, 1, 1), + (1, 0, 1), + (1, 1, 0), +])] +#[case("$_OR__WRAPPER", [ + (0, 0, 0), + (0, 1, 1), + (1, 0, 1), + (1, 1, 1), +])] +#[case("$_XOR__WRAPPER", [ + (0, 0, 0), + (0, 1, 1), + (1, 0, 1), + (1, 1, 0), +])] +#[case("$_XNOR__WRAPPER", [ + (0, 0, 1), + (0, 1, 0), + (1, 0, 0), + (1, 1, 1), +])] +fn test_module_binary_cell(#[case] cell: &str, #[case] cases: [(u8, u8, u8); 4]) { + let cell_type = cell.strip_suffix("_WRAPPER").unwrap(); + let torder = HashMap::from([(cell, vec![cell_type])]); + let mut module = + HardwareModule::new(CELL_WRAPPER_NETLIST.clone(), Some(cell), torder, None, None).unwrap(); + + for (a, b, expected) in cases { + module.set_port("A", BitVec::from_int(a, None)).unwrap(); + module.set_port("B", BitVec::from_int(b, None)).unwrap(); + module.eval(); + let actual: u8 = module.get_port("Y").unwrap().to_int(); + assert_eq!(actual, expected, "inputs: `{a}`, `{b}`"); + } +} + +#[rstest] +#[case::andorinvert("$_AOI3__WRAPPER", [ + (0, 0, 0, 1), + (0, 0, 1, 0), + (0, 1, 0, 1), + (0, 1, 1, 0), + (1, 0, 0, 1), + (1, 0, 1, 0), + (1, 1, 0, 0), + (1, 1, 1, 0), +])] +#[case::orandinvert("$_OAI3__WRAPPER", [ + (0, 0, 0, 1), + (0, 0, 1, 1), + (0, 1, 0, 1), + (0, 1, 1, 0), + (1, 0, 0, 1), + (1, 0, 1, 0), + (1, 1, 0, 1), + (1, 1, 1, 0), +])] +fn test_module_ternary_cell(#[case] cell: &str, #[case] cases: [(u8, u8, u8, u8); 8]) { + let cell_type = cell.strip_suffix("_WRAPPER").unwrap(); + let torder = HashMap::from([(cell, vec![cell_type])]); + let mut module = + HardwareModule::new(CELL_WRAPPER_NETLIST.clone(), Some(cell), torder, None, None).unwrap(); + + for (a, b, c, expected) in cases { + module.set_port("A", BitVec::from_int(a, None)).unwrap(); + module.set_port("B", BitVec::from_int(b, None)).unwrap(); + module.set_port("C", BitVec::from_int(c, None)).unwrap(); + module.eval(); + let actual: u8 = module.get_port("Y").unwrap().to_int(); + assert_eq!(actual, expected, "inputs: `{a}`, `{b}`, `{c}`"); + } +} + +#[rstest] +#[case::mux2("$_MUX__WRAPPER", [ + (0, 0, 0, 0), + (0, 0, 1, 0), + (0, 1, 0, 0), + (0, 1, 1, 1), + (1, 0, 0, 1), + (1, 0, 1, 0), + (1, 1, 0, 1), + (1, 1, 1, 1), +])] +#[case::nmux2("$_NMUX__WRAPPER", [ + (0, 0, 0, 1), + (0, 0, 1, 1), + (0, 1, 0, 1), + (0, 1, 1, 0), + (1, 0, 0, 0), + (1, 0, 1, 1), + (1, 1, 0, 0), + (1, 1, 1, 0), +])] +fn test_module_mux_cell(#[case] cell: &str, #[case] cases: [(u8, u8, u8, u8); 8]) { + let cell_type = cell.strip_suffix("_WRAPPER").unwrap(); + let torder = HashMap::from([(cell, vec![cell_type])]); + let mut module = + HardwareModule::new(CELL_WRAPPER_NETLIST.clone(), Some(cell), torder, None, None).unwrap(); + + for (a, b, s, expected) in cases { + module.set_port("A", BitVec::from_int(a, None)).unwrap(); + module.set_port("B", BitVec::from_int(b, None)).unwrap(); + module.set_port("S", BitVec::from_int(s, None)).unwrap(); + module.eval(); + let actual: u8 = module.get_port("Y").unwrap().to_int(); + assert_eq!(actual, expected, "inputs: `{a}`, `{b}`, `{s}`"); + } +} +// TODO: Expand testing diff --git a/crates/arbolta/tests/test_simlib_module.rs b/crates/arbolta/tests/test_simlib_module.rs new file mode 100644 index 0000000..f3cf835 --- /dev/null +++ b/crates/arbolta/tests/test_simlib_module.rs @@ -0,0 +1,239 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +mod helpers; + +use arbolta::{ + bit::{Bit, BitVec}, + hardware_module::HardwareModule, + yosys::PortDirection, +}; +use helpers::{build_netlist, int_to_attr}; +use indexmap::indexmap; +use rstest::rstest; + +#[rstest] +// 37738 + 4365 = 42103 +#[case::unsigned_normal(false, "1001001101101010", "0001000100001101", "1010010001110111")] +// 155 + 7 = 162 +#[case::unsigned_normal(false, "10011011", "111", "0000000010100010")] +// 54 + 4234 = 4288 +#[case::unsigned_normal(false, "00110110", "0001000010001010", "1000011000000")] +// 37738 + 4365 = 1143 +#[case::unsigned_overflow(false, "1001001101101010", "0001000100001101", "0010001110111")] +#[case(false, "00000111", "00000111", "00001110")] // 7 + 7 = 49 +#[case(false, "00000111", "111", "01110")] // 7 + 7 = 49 +#[case(false, "111", "111", "1110")] // 7 + 7 = 14 +#[case(false, "111", "111", "10")] // 7 + 7 = 4 (overflow) +#[case(true, "00000111", "00000111", "00001110")] // 7 + 7 = 49 +#[case(true, "00000111", "1001", "00000")] // 7 + -7 = 0 +#[case(true, "1001", "11001", "11110010")] // -7 + -7 = -14 +#[case(true, "1001", "1001", "10")] // -7 + -7 = -4 (overflow) +#[case(true, "111", "111", "10")] // 7 + 7 = 4 (overflow) +#[case(true, "1", "0", "111111111111")] // sign extend +#[case(true, "0", "1", "111111111111")] // sign extend +#[case(true, "1", "1", "111111111110")] // -1 + -1 = -2 +#[case(true, "01", "1", "000000000000")] // 1 + -1 = 0 +fn test_add(#[case] signed: bool, #[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + let (netlist, torder) = build_netlist( + "$add", + "$add_wrapper", + indexmap! { + "A_SIGNED" => int_to_attr(signed as u32), + "B_SIGNED" => int_to_attr(signed as u32), + "Y_SIGNED" => int_to_attr(signed as u32), + "A_WIDTH" => int_to_attr(a.len() as u32), + "B_WIDTH" => int_to_attr(b.len() as u32), + "Y_WIDTH" => int_to_attr(expected.len() as u32), + }, + indexmap! { + "A" => (PortDirection::Input, a.len()), + "B" => (PortDirection::Input, b.len()), + "Y" => (PortDirection::Output, expected.len()), + }, + ); + + let mut module = HardwareModule::new(netlist, None, torder, None, None).unwrap(); + + module.set_port("A", a).unwrap(); + module.set_port("B", b).unwrap(); + module.eval(); + + let actual = module.get_port("Y").unwrap(); + assert_eq!(actual, expected); +} + +#[rstest] +#[case(Bit::ZERO, "000", "001", "000")] +#[case(Bit::ONE, "000", "001", "001")] +#[case(Bit::ZERO, "111", "000", "111")] +#[case(Bit::ONE, "111", "000", "000")] +fn test_mux(#[case] select: Bit, #[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + let (netlist, torder) = build_netlist( + "$mux", + "$mux_wrapper", + indexmap! { + "WIDTH" => int_to_attr(a.len() as u32), + }, + indexmap! { + "A" => (PortDirection::Input, a.len()), + "B" => (PortDirection::Input, b.len()), + "S" => (PortDirection::Input, 1), + "Y" => (PortDirection::Output, expected.len()), + }, + ); + + let mut module = HardwareModule::new(netlist, None, torder, None, None).unwrap(); + + module.set_port("S", [select]).unwrap(); + module.set_port("A", a).unwrap(); + module.set_port("B", b).unwrap(); + module.eval(); + + let actual = module.get_port("Y").unwrap(); + assert_eq!(actual, expected); +} + +#[rstest] +#[case::zero(Bit::ONE, "000000000000")] // 0 +#[case::one(Bit::ONE, "000000000001")] // 1 +#[case(Bit::ONE, "1101111001101100")] // 56940 +#[case(Bit::ZERO, "000000000000")] // 0 +#[case(Bit::ZERO, "000000000001")] // 1 +#[case(Bit::ZERO, "1101111001101100")] // 56940 +fn test_reg(#[case] polarity: Bit, #[case] data_in: BitVec) { + let (netlist, torder) = build_netlist( + "$dff", + "$dff_wrapper", + indexmap! { + "CLK_POLARITY" => int_to_attr(polarity.to_int()), + "WIDTH" => int_to_attr(data_in.len() as u32), + }, + indexmap! { + "CLK" => (PortDirection::Input, 1), + "D" => (PortDirection::Input, data_in.len()), + "Q" => (PortDirection::Output, data_in.len()), + }, + ); + + let mut module = HardwareModule::new(netlist, None, torder, None, None).unwrap(); + let clock_net = module.get_net("CLK").unwrap()[0]; + module.set_clock(clock_net, polarity).unwrap(); + + module.set_port("CLK", [!polarity]).unwrap(); // Reset + module.eval(); + assert_eq!(module.get_port("Q").unwrap().to_int::(), 0); + + module.set_port("D", &data_in).unwrap(); + assert_eq!(module.get_port("Q").unwrap().to_int::(), 0); + + module.eval_clocked(Some(1)).unwrap(); + assert_eq!(module.get_port("Q").unwrap(), data_in); + + module.set_port("D", BitVec::from_int(0, None)).unwrap(); // Zero + assert_eq!(module.get_port("Q").unwrap(), data_in); + + module.eval_clocked(Some(1)).unwrap(); + assert_eq!(module.get_port("Q").unwrap().to_int::(), 0); +} + +#[rstest] +#[case("0", "0", "0")] +#[case("0", "1", "0")] +#[case("1", "0", "0")] +#[case("1", "1", "1")] +#[case("00000000", "0000000", "0000")] +#[case("10000000", "0000001", "0001")] +#[case("1", "0000001", "01")] +#[case("1111111", "01", "01")] +#[case("1010100", "0000", "00000")] +fn test_logic_and(#[case] a: BitVec, #[case] b: BitVec, #[case] expected: BitVec) { + let (netlist, torder) = build_netlist( + "$logic_and", + "$logic_and_wrapper", + indexmap! { + "A_SIGNED" => int_to_attr(false as u32), + "A_WIDTH" => int_to_attr(a.len() as u32), + "B_SIGNED" => int_to_attr(false as u32), + "B_WIDTH" => int_to_attr(b.len() as u32), + "Y_WIDTH" => int_to_attr(expected.len() as u32), + }, + indexmap! { + "A" => (PortDirection::Input, a.len()), + "B" => (PortDirection::Input, b.len()), + "Y" => (PortDirection::Output, expected.len()), + }, + ); + + let mut module = HardwareModule::new(netlist, None, torder, None, None).unwrap(); + + module.set_port("A", a).unwrap(); + module.set_port("B", b).unwrap(); + module.eval(); + + let actual = module.get_port("Y").unwrap(); + assert_eq!(actual, expected); +} + +#[rstest] +#[case("0", "1")] +#[case("1", "0")] +#[case("00000000", "0000001")] +#[case("10000000", "0000000")] +#[case("1", "0000000")] +#[case("1111111", "00")] +#[case("1010100", "00")] +fn test_logic_not(#[case] a: BitVec, #[case] expected: BitVec) { + let (netlist, torder) = build_netlist( + "$logic_not", + "$logic_not_wrapper", + indexmap! { + "A_SIGNED" => int_to_attr(false as u32), + "A_WIDTH" => int_to_attr(a.len() as u32), + "Y_WIDTH" => int_to_attr(expected.len() as u32), + }, + indexmap! { + "A" => (PortDirection::Input, a.len()), + "Y" => (PortDirection::Output, expected.len()), + }, + ); + + let mut module = HardwareModule::new(netlist, None, torder, None, None).unwrap(); + + module.set_port("A", a).unwrap(); + module.eval(); + + let actual = module.get_port("Y").unwrap(); + assert_eq!(actual, expected); +} + +#[rstest] +#[case("0", "0")] +#[case("00000000", "0000000")] +#[case("10000000", "0000001")] +#[case("1", "0000001")] +#[case("1111111", "01")] +#[case("1010100", "01")] +fn test_reduce_or(#[case] a: BitVec, #[case] expected: BitVec) { + let (netlist, torder) = build_netlist( + "$reduce_or", + "$reduce_or_wrapper", + indexmap! { + "A_SIGNED" => int_to_attr(false as u32), + "A_WIDTH" => int_to_attr(a.len() as u32), + "Y_WIDTH" => int_to_attr(expected.len() as u32), + }, + indexmap! { + "A" => (PortDirection::Input, a.len()), + "Y" => (PortDirection::Output, expected.len()), + }, + ); + + let mut module = HardwareModule::new(netlist, None, torder, None, None).unwrap(); + + module.set_port("A", a).unwrap(); + module.eval(); + + let actual = module.get_port("Y").unwrap(); + assert_eq!(actual, expected); +} diff --git a/crates/arbolta/tests/test_synth.rs b/crates/arbolta/tests/test_synth.rs deleted file mode 100644 index 863d249..0000000 --- a/crates/arbolta/tests/test_synth.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use arbolta::cell::default_cell_library; -use arbolta::synth::netlist::Netlist; - -static ADDER_RAW: &str = include_str!("test_netlists/4b_adder_netlist.json"); -static NESTED_ADDER_RAW: &str = include_str!("test_netlists/4b_nested_adder_netlist.json"); - -#[test] -fn test_synth_4b_adder() { - let netlist = Netlist::from_yosys_raw(ADDER_RAW.as_bytes()).unwrap(); - let mut adder_module = netlist - .generate_module("adder", &default_cell_library()) - .unwrap(); - - for a in 0..16_u8 { - adder_module.set_port_int("op0_i", a).unwrap(); - for b in 0..16_u8 { - adder_module.set_port_int("op1_i", b).unwrap(); - adder_module.eval(); - let actual_sum = adder_module.get_port_int::("sum_o").unwrap(); - let expected_sum = a + b; - - assert_eq!(actual_sum, expected_sum) - } - } -} - -#[test] -fn test_synth_4b_nested_adder() { - let netlist = Netlist::from_yosys_raw(NESTED_ADDER_RAW.as_bytes()).unwrap(); - let mut adder_module = netlist - .generate_module("adder", &default_cell_library()) - .unwrap(); - - for a in 0..16_u8 { - adder_module.set_port_int("op0_i", a).unwrap(); - for b in 0..16_u8 { - adder_module.set_port_int("op1_i", b).unwrap(); - adder_module.eval(); - let actual_sum = adder_module.get_port_int::("sum_o").unwrap(); - let expected_sum = a + b; - - assert_eq!(actual_sum, expected_sum) - } - } -} diff --git a/crates/arbolta_pyo3/Cargo.toml b/crates/arbolta_pyo3/Cargo.toml new file mode 100644 index 0000000..5dc9f0c --- /dev/null +++ b/crates/arbolta_pyo3/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "arbolta_pyo3" +version = "0.1.0" +authors = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +readme = "../../README.md" +description = "Python bindings for Arbolta hardware simulator" + +[lib] +name = "arbolta" +crate-type = ["cdylib"] + +[dependencies] +anyhow = "*" +arbolta = { workspace = true } +num-traits = { workspace = true } +numpy = "0.27" +petgraph = { workspace = true } +pyo3 = { version = "0.27", features = ["anyhow"] } +serde = { version = "1.0", features = ["derive"] } +thiserror = { workspace = true } diff --git a/crates/arbolta_pyo3/src/conversion.rs b/crates/arbolta_pyo3/src/conversion.rs new file mode 100644 index 0000000..3db578c --- /dev/null +++ b/crates/arbolta_pyo3/src/conversion.rs @@ -0,0 +1,48 @@ +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use arbolta::bit::BitVec; +use num_traits::{PrimInt, WrappingAdd, WrappingShl, WrappingSub}; +use numpy::{PyArrayMethods, PyReadonlyArray1, PyReadwriteArray1}; +use pyo3::prelude::*; + +pub fn bits_to_bool_numpy(bits: &BitVec, numpy_array: &Bound<'_, PyAny>) -> PyResult<()> { + let mut buffer = numpy_array.extract::>()?; + + bits + .bits + .iter() + .zip(buffer.as_array_mut().iter_mut()) + .for_each(|(&bit, buf)| *buf = bit.0); + + Ok(()) +} + +pub fn bool_numpy_to_bits(numpy_array: &Bound<'_, PyAny>) -> PyResult { + let buffer = numpy_array.extract::>()?; + Ok(BitVec::from_iter(buffer.to_owned_array())) +} + +pub fn bits_to_int_numpy( + bits: &BitVec, + elem_size: usize, + numpy_array: &Bound<'_, PyAny>, +) -> PyResult<()> { + let mut buffer = numpy_array.extract::>()?; + + bits + .to_ints(Some(elem_size)) + .zip(buffer.as_array_mut().iter_mut()) + .for_each(|(src, dst)| *dst = src); + + Ok(()) +} + +pub fn int_numpy_to_bits( + numpy_array: &Bound<'_, PyAny>, + elem_size: usize, +) -> PyResult { + let buffer = numpy_array.extract::>()?; + Ok(BitVec::from_ints(buffer.to_owned_array(), Some(elem_size))) +} diff --git a/crates/arbolta_pyo3/src/hardware_module.rs b/crates/arbolta_pyo3/src/hardware_module.rs new file mode 100644 index 0000000..89c5d1d --- /dev/null +++ b/crates/arbolta_pyo3/src/hardware_module.rs @@ -0,0 +1,361 @@ +// Copyright (c) 2024 Advanced Micro Devices, Inc. +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use crate::conversion::{ + bits_to_bool_numpy, bits_to_int_numpy, bool_numpy_to_bits, int_numpy_to_bits, +}; +use crate::ports::{PortConfig, Ports}; +use arbolta::{ + bit::Bit, + cell::CellMapping, + hardware_module::{HardwareModule, ToggleCount}, + port::{PortDirection, parse_bit}, + yosys::{Netlist, parse_torder}, +}; +use petgraph::visit::EdgeRef; +use pyo3::{ + exceptions::{PyAttributeError, PyValueError}, + prelude::*, + types::{PyDict, PyList}, +}; +use serde::{Deserialize, Serialize}; +use std::{ + collections::{HashMap, HashSet}, + path::PathBuf, +}; + +#[pyclass(weakref, dict)] +#[derive(Deserialize, Serialize)] +pub struct HardwareDesign { + pub module: HardwareModule, +} + +impl HardwareDesign { + fn new_base( + netlist_path: PathBuf, + top_module: Option<&str>, + torder_path: PathBuf, + hierarchy_separator: Option<&str>, + cell_mapping: Option<&CellMapping>, + ) -> anyhow::Result { + // Read raw JSON netlist + let raw_netlist = std::fs::read(netlist_path)?; + let netlist = Netlist::from_slice(&raw_netlist)?; + + // Read raw torder + let raw_torder = std::fs::read_to_string(torder_path)?; + let torder = parse_torder(&raw_torder); + + let module = HardwareModule::new( + netlist, + top_module, + torder, + hierarchy_separator, + cell_mapping, + )?; + + Ok(Self { module }) + } + + pub fn get_port_shape(&self, name: &str) -> anyhow::Result<[usize; 2]> { + Ok(self.module.get_port_shape(name)?) + } + + pub fn get_port_numpy(&self, name: &str, numpy_array: &Bound<'_, PyAny>) -> PyResult<()> { + let item_type = numpy_array.getattr("dtype")?.getattr("str")?.to_string(); + let elem_size = self.get_port_shape(name)?[1]; + + let bits = self + .module + .get_port(name) + .map_err(|e| PyAttributeError::new_err(format!("{e}")))?; + + match item_type.as_str() { + "|b1" => bits_to_bool_numpy(&bits, numpy_array), + "|u1" | " bits_to_int_numpy::(&bits, elem_size, numpy_array), + " bits_to_int_numpy::(&bits, elem_size, numpy_array), + " bits_to_int_numpy::(&bits, elem_size, numpy_array), + " bits_to_int_numpy::(&bits, elem_size, numpy_array), + "|i1" => bits_to_int_numpy::(&bits, elem_size, numpy_array), + " bits_to_int_numpy::(&bits, elem_size, numpy_array), + " bits_to_int_numpy::(&bits, elem_size, numpy_array), + " bits_to_int_numpy::(&bits, elem_size, numpy_array), + // Cast f16 to u16 + " bits_to_int_numpy::( + &bits, + elem_size, + &numpy_array.call_method1("view", ("uint16",))?, + ), + // Cast f32 to u32 + " bits_to_int_numpy::( + &bits, + elem_size, + &numpy_array.call_method1("view", ("uint32",))?, + ), + _ => Err(PyValueError::new_err(format!( + "Unsupported item type: {item_type}" + ))), + } + } + + pub fn set_port_numpy(&mut self, name: &str, numpy_array: &Bound<'_, PyAny>) -> PyResult<()> { + let item_type: String = numpy_array.getattr("dtype")?.getattr("str")?.to_string(); + let shape = self.get_port_shape(name)?; + let elem_size = shape[1]; + + let bits = match item_type.as_str() { + "|b1" => bool_numpy_to_bits(numpy_array)?, + "|u1" => int_numpy_to_bits::(numpy_array, elem_size)?, + " int_numpy_to_bits::(numpy_array, elem_size)?, + " int_numpy_to_bits::(numpy_array, elem_size)?, + " int_numpy_to_bits::(numpy_array, elem_size)?, + "|i1" => int_numpy_to_bits::(numpy_array, elem_size)?, + " int_numpy_to_bits::(numpy_array, elem_size)?, + " int_numpy_to_bits::(numpy_array, elem_size)?, + " int_numpy_to_bits::(numpy_array, elem_size)?, + // Cast to raw uint8 + " int_numpy_to_bits::(&numpy_array.call_method1("view", ("uint8",))?, elem_size)?, + // Cast f16 to u16 + " { + int_numpy_to_bits::(&numpy_array.call_method1("view", ("uint16",))?, elem_size)? + } + // Cast f32 to u32 + " { + int_numpy_to_bits::(&numpy_array.call_method1("view", ("uint32",))?, elem_size)? + } + _ => { + return Err(PyValueError::new_err(format!( + "Unsupported item type: {item_type}" + ))); + } + }; + + self + .module + .set_port(name, bits) + .map_err(|e| PyAttributeError::new_err(format!("{e}"))) + } +} + +#[pymethods] +impl HardwareDesign { + #[new] + #[pyo3(signature = (netlist_path, torder_path, config, hierarchy_separator=None, top_module=None, cell_mapping=None))] + pub fn new( + py: Python<'_>, + netlist_path: PathBuf, + torder_path: PathBuf, + config: HashMap>, + hierarchy_separator: Option<&str>, + top_module: Option<&str>, + cell_mapping: Option, + ) -> anyhow::Result> { + let new_module = Self::new_base( + netlist_path, + top_module, + torder_path, + hierarchy_separator, + cell_mapping.as_ref(), + )?; + + // Get submodules before binding to Python + let submodules = new_module + .module + .netlist + .modules + .iter() + .map(|p| p.join(".")) + .collect::>(); + + let py_module = Py::new(py, new_module)?; + + // Add custom members (can't make them static for serialization) + let temp_binding = py_module.getattr(py, "__dict__")?; + let temp_dict = temp_binding.cast_bound::(py).unwrap(); + + // Add ports field + let ports = Py::new(py, Ports::new(py, config, py_module.clone_ref(py))?)?; + temp_dict.set_item("ports", ports)?; + + // Add modules/submodules field + temp_dict.set_item("modules", PyList::new(py, submodules)?)?; + + Ok(py_module) + } + + pub fn reset(&mut self) { + self.module.reset() + } + + pub fn eval(&mut self) { + self.module.eval() + } + + #[pyo3(signature = (cycles=None))] + pub fn eval_clocked(&mut self, cycles: Option) -> anyhow::Result<()> { + Ok(self.module.eval_clocked(cycles)?) + } + + #[pyo3(signature = (cycles=None))] + pub fn eval_reset_clocked(&mut self, cycles: Option) -> anyhow::Result<()> { + Ok(self.module.eval_reset_clocked(cycles)?) + } + + pub fn stick_signal(&mut self, net: usize, val: u8) -> anyhow::Result<()> { + Ok(self.module.stick_signal(net, Bit::from_int(val)?)?) + } + + pub fn unstick_signal(&mut self, net: usize) -> anyhow::Result<()> { + Ok(self.module.unstick_signal(net)?) + } + + pub fn is_port_input(&self, name: &str) -> anyhow::Result { + let direction = self.module.get_port_direction(name)?; + Ok(direction == PortDirection::Input) + } + + #[pyo3(signature = (category="total", by_net=true))] + pub fn toggle_count(&self, py: Python<'_>, category: &str, by_net: bool) -> PyResult> { + let category = match category { + "falling" => ToggleCount::Falling, + "rising" => ToggleCount::Rising, + "total" => ToggleCount::Total, + _ => { + return Err(PyValueError::new_err(format!( + "Invalid toggle category `{category}`" + ))); + } + }; + + let toggles = PyDict::new(py); + if by_net { + for (submodule_names, nets_ref) in self.module.get_submodule_toggles_by_net(category) { + let name = submodule_names.join("."); + let nets: HashMap = nets_ref + .into_iter() + .map(|(n, c)| (n.to_string(), c)) + .collect(); + + toggles.set_item(name, nets)?; + } + } else { + for (submodule_names, count) in self.module.get_submodule_toggles_total(category) { + let name = submodule_names.join("."); + + toggles.set_item(name, count)?; + } + } + + Ok(toggles.into()) + } + + pub fn netlist(&self, py: Python<'_>) -> PyResult> { + let json = py.import("json")?; + let netlist = self + .module + .netlist + .netlist + .to_string() + .map_err(|e| PyAttributeError::new_err(format!("{e}")))?; + + let netlist_dict: Bound<'_, PyDict> = json.getattr("loads")?.call1((netlist,))?.cast_into()?; + Ok(netlist_dict.unbind()) + } + + pub fn netlist_graph(&self, py: Python<'_>) -> PyResult> { + let networkx = py.import("networkx")?; + + let graph = self + .module + .netlist + .build_graph() + .map_err(|e| PyAttributeError::new_err(format!("{e}")))?; + + let nx_graph = networkx.getattr("DiGraph")?.call0()?; + + // Add nodes + let mut nodes: Vec<(usize, Py)> = vec![]; + for i in graph.node_indices() { + let rtlid = graph.node_weight(i).unwrap(); + + let entry = PyDict::new(py); + entry.set_item("rtlid", rtlid.to_string())?; + + // $input or $output cell, early continue + let Some(cell) = self.module.netlist.find_cell(rtlid) else { + nodes.push((i.index(), entry.unbind())); + continue; + }; + + // Extract other fields + entry.set_item("cell_type", cell.cell_type.clone())?; + + if let Some(src_attr) = cell.attributes.get("src") + && let Some(src) = src_attr.to_string_if_string() + { + entry.set_item("src", src.to_string())?; + } + + nodes.push((i.index(), entry.unbind())); + } + nx_graph.call_method1("add_nodes_from", (nodes,))?; + + // Add edges + let mut edges: Vec<(usize, usize, Py)> = vec![]; + for edge in graph.edge_references() { + let net_driver_node = edge.source(); + let net_user_node = edge.target(); + + let net_driver = graph.node_weight(net_driver_node).unwrap(); + let net_user = graph.node_weight(net_user_node).unwrap(); + let net = *edge.weight(); + + let entry = PyDict::new(py); + entry.set_item("net", net)?; + + if let Some(driver_cell) = self.module.netlist.find_cell(net_driver) { + for (port_name, bits) in &driver_cell.connections { + // TODO: pre-process this somehow + let nets = HashSet::::from_iter( + bits + .iter() + .map(parse_bit) + .collect::, _>>() + .map_err(|e| PyAttributeError::new_err(format!("{e}")))?, + ); + + if nets.contains(&net) { + entry.set_item("driver", port_name.clone())?; + } + } + } + + if let Some(user_cell) = self.module.netlist.find_cell(net_user) { + for (port_name, bits) in &user_cell.connections { + // TODO: pre-process this somehow + let nets = HashSet::::from_iter( + bits + .iter() + .map(parse_bit) + .collect::, _>>() + .map_err(|e| PyAttributeError::new_err(format!("{e}")))?, + ); + + if nets.contains(&net) { + entry.set_item("user", port_name.clone())?; + } + } + } + + edges.push(( + net_driver_node.index(), + net_user_node.index(), + entry.unbind(), + )); + } + nx_graph.call_method1("add_edges_from", (edges,))?; + + Ok(nx_graph.into()) + } +} diff --git a/crates/arbolta_pyo3/src/lib.rs b/crates/arbolta_pyo3/src/lib.rs new file mode 100644 index 0000000..cf3fb77 --- /dev/null +++ b/crates/arbolta_pyo3/src/lib.rs @@ -0,0 +1,16 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use pyo3::prelude::*; +mod conversion; +mod hardware_module; +mod ports; + +#[pymodule] +fn arbolta(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + + Ok(()) +} diff --git a/crates/arbolta_pyo3/src/ports.rs b/crates/arbolta_pyo3/src/ports.rs new file mode 100644 index 0000000..14730ad --- /dev/null +++ b/crates/arbolta_pyo3/src/ports.rs @@ -0,0 +1,205 @@ +// Copyright (c) 2026 Alexander Redding +// SPDX-License-Identifier: MIT + +use crate::hardware_module::HardwareDesign; +use arbolta::{bit::Bit, port::PortDirection}; +use pyo3::{ + exceptions::{PyAttributeError, PyValueError}, + prelude::*, + types::PyDict, +}; +use std::collections::{HashMap, HashSet}; + +// Treat as a dataclass +#[pyclass] +pub struct PortConfig { + #[pyo3(get, set)] + pub shape: (usize, usize), // Defaults (1,1) + #[pyo3(get, set)] + pub dtype: Py, // Numpy datatype, defaults to np.uint + #[pyo3(get, set)] + pub clock: bool, + #[pyo3(get, set)] + pub reset: bool, + #[pyo3(get, set)] + pub polarity: Option, // Literal [0, 1] +} + +#[pymethods] +impl PortConfig { + #[new] + #[pyo3(signature = (shape=(1,1), dtype=None, clock=false, reset=false, polarity=None))] + fn new( + py: Python<'_>, + shape: (usize, usize), + dtype: Option>, + clock: bool, + reset: bool, + polarity: Option, + ) -> PyResult { + let dtype = match dtype { + Some(d) => d, + None => py.import("numpy")?.getattr("uint")?.into(), + }; + + Ok(Self { + shape, + dtype, + clock, + reset, + polarity, + }) + } +} + +#[pyclass(dict)] +pub struct Ports { + module: Py, + input_ports: HashSet, + output_ports: HashSet, +} + +#[pymethods] +impl Ports { + fn __setattr__(self_: Bound<'_, Self>, name: &str, value: &Bound<'_, PyAny>) -> PyResult<()> { + let binding = &mut self_.borrow(); + + if binding.output_ports.contains(name) { + return Err(PyAttributeError::new_err(format!( + "Cannot set output port `{name}`" + ))); + } + + if !binding.input_ports.contains(name) { + return Err(PyAttributeError::new_err(format!( + "Port `{name}` doesn't exist" + ))); + } + + let py = self_.py(); + let object_type = py + .get_type::() + .py() + .import("builtins")? + .getattr("object")?; + + let buffer_ref = object_type.call_method1("__getattribute__", (&self_, name))?; + + let np = py.import("numpy")?; + np.getattr("copyto")?.call1((&buffer_ref, value))?; + + binding + .module + .borrow_mut(py) + .set_port_numpy(name, &buffer_ref)?; + + Ok(()) + } + + fn __getattribute__(self_: Bound<'_, Self>, name: &str) -> PyResult> { + let binding = &mut self_.borrow(); + + let py = self_.py(); + let object_type = py + .get_type::() + .py() + .import("builtins")? + .getattr("object")?; + let buffer_ref = object_type.call_method1("__getattribute__", (&self_, name))?; + + // Update + if binding.output_ports.contains(name) { + binding + .module + .borrow_mut(py) + .get_port_numpy(name, &buffer_ref)?; + } + + Ok(buffer_ref.into()) + } +} + +impl Ports { + fn new_base(module: Py) -> Self { + Self { + module, + input_ports: Default::default(), + output_ports: Default::default(), + } + } + + pub fn new( + py: Python<'_>, + config: HashMap>, + module: Py, + ) -> anyhow::Result> { + let np = py.import("numpy")?; + let module_ref = &mut module.bind(py).borrow_mut().module; + + let new_self = Py::new(py, Self::new_base(module))?; + let temp_binding = new_self.getattr(py, "__dict__")?; + let ports = temp_binding.cast_bound::(py).unwrap(); + + let binding = &mut new_self.bind(py).borrow_mut(); + + let port_names: Vec = module_ref.ports.keys().cloned().collect(); + for port_name in port_names { + let direction = module_ref.get_port_direction(&port_name)?; + let kwargs = PyDict::new(py); + let buffer_len: usize; + + if let Some(port_config) = config.get(&port_name) { + if port_config.reset || port_config.clock { + if let Some(polarity) = port_config.polarity { + let polarity = Bit::from_int(polarity)?; + let nets = module_ref + .get_net(&port_name) + .ok_or(PyAttributeError::new_err(format!("No net `{port_name}`")))?; + + if nets.len() != 1 { + return Err(PyAttributeError::new_err(">1 clock or reset bits".to_string()).into()); + } + + let net = *nets.first().unwrap(); + if port_config.reset { + module_ref.set_reset(net, polarity)?; + } + + if port_config.clock { + module_ref.set_clock(net, polarity)?; + } + } else { + return Err(PyValueError::new_err("No polarity given".to_string()).into()); + } + } + + let shape: [usize; 2] = [port_config.shape.0, port_config.shape.1]; + + if shape[0] != 1 { + return Err(PyValueError::new_err(format!("Only 1D shapes supported: {shape:?}")).into()); + } + + let internal_shape = module_ref.get_port_shape(&port_name)?; + let (num_elems, elem_size) = (shape[1], internal_shape[1] / shape[1]); + module_ref.set_port_shape(&port_name, &[num_elems, elem_size])?; + kwargs.set_item("dtype", port_config.dtype.bind(py))?; + buffer_len = num_elems; + // No config given + } else { + kwargs.set_item("dtype", np.getattr("uint")?)?; + buffer_len = module_ref.get_port_shape(&port_name)?[0]; + } + + let buffer = np.getattr("zeros")?.call((buffer_len,), Some(&kwargs))?; + ports.set_item(port_name.clone(), buffer)?; + + match direction { + PortDirection::Input => &mut binding.input_ports, + PortDirection::Output => &mut binding.output_ports, + } + .insert(port_name); + } + + Ok(new_self) + } +} diff --git a/crates/python_bindings/Cargo.toml b/crates/python_bindings/Cargo.toml deleted file mode 100644 index fe879ed..0000000 --- a/crates/python_bindings/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "arbolta-python" -version = "0.1.0" -authors = ["AMD Research & Advanced Development"] -edition = "2021" - -[lib] -name = "arbolta" -crate-type = ["cdylib"] - -[dependencies] -pyo3 = "0.23.3" -numpy = "0.23.0" -num-traits = "0.2" -serde = { version = "1.0", features = ["derive"] } -bincode = "1.3.3" - -[dependencies.arbolta] -path = "../arbolta" - -[features] -defaut = ["pyo3/extension-module"] diff --git a/crates/python_bindings/py_src/arbolta/__init__.py b/crates/python_bindings/py_src/arbolta/__init__.py deleted file mode 100644 index b923124..0000000 --- a/crates/python_bindings/py_src/arbolta/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -# SPDX-License-Identifier: MIT - -from .arbolta import Design # For pickling -from .design import * diff --git a/crates/python_bindings/py_src/arbolta/design.py b/crates/python_bindings/py_src/arbolta/design.py deleted file mode 100644 index df79b14..0000000 --- a/crates/python_bindings/py_src/arbolta/design.py +++ /dev/null @@ -1,253 +0,0 @@ -# Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -# SPDX-License-Identifier: MIT - -from dataclasses import dataclass -from typing import Any, Dict, List, Optional, Tuple, TypedDict - -import numpy as np - -from .arbolta import Design - -__all__ = ["PortConfig", "DesignConfig", "HardwareDesign"] - - -@dataclass -class PortConfig: - """ - Configuration for a HardwareDesign port. - - Attributes - ---------- - shape : tuple - Interpret port bits with shape. - dtype : np.dtype - Interpret port bits as type. - clock : bool, optional - Port is a clock signal. - reset : bool, optional - Port is a reset signal. - """ - shape: Tuple[int, int] = (1, 1) - dtype: np.dtype = np.uint32 - clock: bool = False - reset: bool = False - - -class DesignConfig(TypedDict): - """ - Configuration for HardwareDesign. - - Attributes - ---------- - port : str - Name of port. - config : PortConfig - Configuration for port - """ - port: str - config: PortConfig - - -class HardwarePorts: - - def __init__(self, config: DesignConfig, design: Design): - - _ports: Dict[str, np.ndarray] = {} - - port_name: str - port_config: PortConfig - for port_name, port_config in config.items(): - if port_config.reset and port_config.clock: - raise AttributeError( - f"Port `{port_name}` cannot be a reset and clock") - if port_config.reset: - design.set_reset(port_name) - if port_config.clock: - design.set_clock(port_name) - - design.set_port_shape(port_name, port_config.shape) - _ports[port_name] = np.zeros(port_config.shape[1], - dtype=port_config.dtype) - - super().__setattr__('_ports', _ports) - super().__setattr__('_design', design) - - def __getattr__(self, name: str) -> Any: - if '_ports' in self.__dict__ and '_design' in self.__dict__: - _ports = self.__dict__['_ports'] - - if name not in _ports: - raise AttributeError(f"Port `{name}` does not exist") - - _design = self.__dict__['_design'] - - if not _design.is_port_input(name): - _design.get_port_numpy(name, _ports[name]) - - return _ports[name] - - else: - raise AttributeError("Ports not initialized") - - def __setattr__(self, name: str, value: Any) -> None: - if '_ports' in self.__dict__ and '_design' in self.__dict__: - _ports = self.__dict__['_ports'] - - if name not in _ports: - raise AttributeError(f"Port `{name}` does not exist") - - np.copyto(_ports[name], value) - - else: - raise AttributeError("Ports not initialized") - - -class HardwareDesign: - - def __init__(self, top_module: str, netlist_path: str, - config: DesignConfig): - """ - Parameters - ---------- - top_module : str - Name of top module. - netlist_path : str - Path to Yosys netlist JSON. - config : DesignConfig - Configuration for design. - """ - self.top_module = top_module - self.design = Design(top_module, netlist_path) - self.ports = HardwarePorts(config, self.design) - - def reset(self): - """ - Reset all design signals and registers to zero. - Resets all toggle to zero. - """ - self.design.reset() - - def reset_clocked(self): - """ - Asserts reset signal and clocks design for 1 cycle. - - Raises - ------ - AttributeError: No reset and/or clock signal configured. - """ - self.design.reset_clocked() - - def eval(self): - """ - Evaluates all cells in design. - """ - for port_name, port_array in self.ports._ports.items(): - if self.design.is_port_input(port_name): - self.design.set_port_numpy(port_name, port_array) - - self.design.eval() - - def eval_clocked(self): - """ - Clocks and evaluates design for 1 cycle. - - Raises - ------ - AttributeError: No clock signal configured. - """ - for port_name, port_array in self.ports._ports.items(): - if self.design.is_port_input(port_name): - self.design.set_port_numpy(port_name, port_array) - - self.design.eval_clocked() - - def cell_breakdown(self, - module_name: Optional[str] = None) -> Dict[str, int]: - """ - Get count of each cell type in module. - - Parameters - ---------- - module_name : str, optional - Name of module. Defaults to top module. - - Returns - ------- - breakdown : dict - Dictionary of cell types and their count in given module. - - Raises - ------ - AttributeError: Specified module doesn't exist in design. - """ - if module_name is None: - return self.design.get_module_breakdown(self.design.top_module) - else: - return self.design.get_module_breakdown(module_name) - - def area(self, module_name: Optional[str] = None) -> float: - """ - Get area of module. Area units are specified by cell library used for - synthesis. - - Parameters - ---------- - module_name : str, optional - Name of module. Defaults to top module. - - Returns - ------- - area : float - Area of given module. - - Raises - ------ - AttributeError: Specified module doesn't exist in design. - """ - if module_name is None: - return self.design.get_module_area(self.design.top_module) - else: - return self.design.get_module_area(module_name) - - def total_toggle_count(self, module_name: Optional[str] = None) -> int: - """ - Get total toggle count (rising + falling) of module. - - Parameters - ---------- - module_name : str, optional - Name of module. Defaults to top module. - - Returns - ------- - toggle_count : int - Total toggle count of given module. - - Raises - ------ - AttributeError: Specified module doesn't exist in design. - """ - if module_name is None: - return self.design.get_module_total_toggle_count( - self.design.top_module) - else: - return self.design.get_module_total_toggle_count(module_name) - - def module_names(self) -> List[str]: - """ - Get names of modules in top-level design module. - - Returns - ------- - modules : list - Module names. - """ - return self.design.get_module_names() - - -def save(file: str, design: HardwareDesign) -> None: - assert RuntimeError("Unimplemented") - - -def load(file: str) -> HardwareDesign: - assert RuntimeError("Unimplemented") diff --git a/crates/python_bindings/pyproject.toml b/crates/python_bindings/pyproject.toml deleted file mode 100644 index fa5abb9..0000000 --- a/crates/python_bindings/pyproject.toml +++ /dev/null @@ -1,23 +0,0 @@ -[project] -name = "arbolta" -requires-python = ">=3.8" -authors = [ - {name = 'AMD Research & Advanced Development'} -] -classifiers = [ - "Programming Language :: Rust", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", -] -dynamic = ["version"] - -dependencies = ["numpy>=2.1"] - -[build-system] -requires = ["maturin>=1.7,<2.0"] -build-backend = "maturin" - -[tool.maturin] -python-source = "py_src" -module-name = "arbolta.arbolta" -features = ["pyo3/extension-module"] diff --git a/crates/python_bindings/src/conversion.rs b/crates/python_bindings/src/conversion.rs deleted file mode 100644 index 30b3baf..0000000 --- a/crates/python_bindings/src/conversion.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use arbol::bit::BitVec; -use num_traits::PrimInt; -use numpy::{PyReadonlyArray1, PyReadwriteArray1}; -use pyo3::exceptions::PyValueError; -use pyo3::prelude::*; - -pub fn bits_to_bool_numpy(bits: &BitVec, numpy_array: &Bound<'_, PyAny>) -> PyResult<()> { - let mut buffer = numpy_array.extract::>()?; - match bits.to_bool_ndarray_buffer(buffer.as_array_mut()) { - Ok(()) => Ok(()), - Err(err) => Err(PyValueError::new_err(format!("{err}"))), - } -} - -pub fn bool_numpy_to_bits(numpy_array: &Bound<'_, PyAny>) -> PyResult { - let buffer = numpy_array.extract::>()?; - - match BitVec::from_bool_ndarray(buffer.as_array()) { - Ok(bits) => Ok(bits), - Err(err) => Err(PyValueError::new_err(format!("{err}"))), - } -} - -pub fn bits_to_int_numpy( - bits: &BitVec, - elem_size: usize, - numpy_array: &Bound<'_, PyAny>, -) -> PyResult<()> { - let mut buffer = numpy_array.extract::>()?; - - match bits.to_int_ndarray_sized_buffer(elem_size, buffer.as_array_mut()) { - Ok(()) => Ok(()), - Err(err) => Err(PyValueError::new_err(format!("{err}"))), - } -} - -pub fn int_numpy_to_bits( - numpy_array: &Bound<'_, PyAny>, - elem_size: usize, -) -> PyResult { - let buffer = numpy_array.extract::>()?; - - match BitVec::from_int_ndarray_sized(buffer.as_array(), elem_size) { - Ok(bits) => Ok(bits), - Err(err) => Err(PyValueError::new_err(format!("{err}"))), - } -} diff --git a/crates/python_bindings/src/design.rs b/crates/python_bindings/src/design.rs deleted file mode 100644 index f8949bd..0000000 --- a/crates/python_bindings/src/design.rs +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -use crate::conversion::{ - bits_to_bool_numpy, bits_to_int_numpy, bool_numpy_to_bits, int_numpy_to_bits, -}; -use arbol::cell::default_cell_library; -use arbol::module::{design::Design, port::PortDirection}; -use arbol::synth::netlist::Netlist; -use bincode; -use pyo3::exceptions::{PyAttributeError, PyException, PyValueError}; -use pyo3::prelude::*; -use pyo3::types::PyBytes; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; - -#[pyclass(dict, module = "arbolta", name = "Design")] -#[derive(Deserialize, Serialize)] -pub struct PyDesign { - #[pyo3(get)] - pub top_module: String, - pub netlist_path: String, - design: Design, -} - -#[pymethods] -impl PyDesign { - #[new] - fn __new__(top_module: &str, netlist_path: &str) -> PyResult { - let cell_library = default_cell_library(); - let netlist = match Netlist::from_yosys(netlist_path) { - Ok(netlist) => netlist, - Err(err) => return Err(PyException::new_err(format!("{err}"))), - }; - - let module = match netlist.generate_module(top_module, &cell_library) { - Ok(module) => module, - Err(err) => return Err(PyException::new_err(format!("{err}"))), - }; - - let design = Design::from_module(module, cell_library); - - Ok(Self { - top_module: top_module.to_string(), - netlist_path: netlist_path.to_string(), - design, - }) - } - - fn __setstate__(&mut self, state: &Bound<'_, PyBytes>) { - *self = bincode::deserialize(state.as_bytes()).unwrap(); - } - - fn __getstate__<'py>(&self, py: Python<'py>) -> PyResult> { - match bincode::serialize(&self) { - Ok(bytes) => Ok(PyBytes::new(py, &bytes)), - Err(err) => Err(PyValueError::new_err(format!("{err}"))), - } - } - - fn __getnewargs__(&self) -> (String, String) { - (self.top_module.clone(), self.netlist_path.clone()) - } - - fn save(&self, path: &str) -> PyResult<()> { - match self.design.save(path) { - Ok(()) => Ok(()), - Err(err) => Err(PyValueError::new_err(format!("{err}"))), - } - } - - fn load(&self, path: &str) -> PyResult { - let design = match Design::load(path) { - Ok(design) => design, - Err(err) => return Err(PyValueError::new_err(format!("{err}"))), - }; - - let top_module = design.module.name.clone(); - - Ok(Self { - top_module, - netlist_path: String::new(), // leave this empty for now, - design, - }) - } - - fn get_port_shape(&self, name: &str) -> PyResult<[usize; 2]> { - match self.design.module.get_port_shape(name) { - Ok(shape) => Ok(shape), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn set_port_shape(&mut self, name: &str, shape: [usize; 2]) -> PyResult<()> { - if shape[0] != 1 { - return Err(PyValueError::new_err(format!( - "Only 1D shapes supported: {shape:?}" - ))); - } - - let internal_shape = self.get_port_shape(name)?; - let (num_elems, elem_size) = (shape[1], internal_shape[1] / shape[1]); - match self - .design - .module - .set_port_shape(name, &[num_elems, elem_size]) - { - Ok(()) => Ok(()), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn get_module_names(&self) -> Vec { - let mut names: Vec = vec![]; - self - .design - .module - .components - .iter() - .for_each(|component| match component { - arbol::module::hardware_module::Component::Cell(_) => (), - arbol::module::hardware_module::Component::Module(module) => { - names.push(module.name.clone()) - } - }); - names - } - - fn set_clock(&mut self, name: &str) -> PyResult<()> { - match self.design.set_clock(name) { - Ok(()) => Ok(()), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn set_reset(&mut self, name: &str) -> PyResult<()> { - match self.design.set_reset(name) { - Ok(()) => Ok(()), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn reset(&mut self) { - self.design.module.reset(); - } - - fn reset_clocked(&mut self) -> PyResult<()> { - match self.design.reset_clocked() { - Ok(()) => Ok(()), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn eval(&mut self) { - self.design.eval(); - } - - fn eval_clocked(&mut self) -> PyResult<()> { - match self.design.eval_clocked() { - Ok(()) => Ok(()), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn get_module_breakdown(&self, name: &str) -> PyResult> { - match self.design.get_module_breakdown(name) { - Ok(breakdown) => Ok(breakdown), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn get_module_area(&self, name: &str) -> PyResult { - match self.design.get_module_area(name) { - Ok(area) => Ok(area), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn get_module_total_toggle_count(&self, name: &str) -> PyResult { - match self.design.get_module_total_toggle_count(name) { - Ok(count) => Ok(count), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn get_port_string(&self, name: &str) -> PyResult { - match self.design.module.get_port_string(name) { - Ok(bit_string) => Ok(bit_string), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } - - fn is_port_input(&self, name: &str) -> PyResult { - let direction = match self.design.module.get_port_direction(name) { - Ok(direction) => direction, - Err(err) => return Err(PyAttributeError::new_err(format!("{err}"))), - }; - - Ok(direction == PortDirection::Input) - } - - fn get_port_numpy(&self, name: &str, numpy_array: &Bound<'_, PyAny>) -> PyResult<()> { - let item_type = numpy_array.getattr("dtype")?.getattr("str")?.to_string(); - let shape = self.get_port_shape(name)?; - let elem_size = shape[1]; - let bits = match self.design.module.get_port_bits(name) { - Ok(bits) => bits, - Err(err) => return Err(PyAttributeError::new_err(format!("{err}"))), - }; - match item_type.as_str() { - "|b1" => bits_to_bool_numpy(&bits, numpy_array), - "|u1" | " bits_to_int_numpy::(&bits, elem_size, numpy_array), - " bits_to_int_numpy::(&bits, elem_size, numpy_array), - " bits_to_int_numpy::(&bits, elem_size, numpy_array), - " bits_to_int_numpy::(&bits, elem_size, numpy_array), - "|i1" => bits_to_int_numpy::(&bits, elem_size, numpy_array), - " bits_to_int_numpy::(&bits, elem_size, numpy_array), - " bits_to_int_numpy::(&bits, elem_size, numpy_array), - " bits_to_int_numpy::(&bits, elem_size, numpy_array), - // Cast f16 to u16 - " bits_to_int_numpy::( - &bits, - elem_size, - &numpy_array.call_method1("view", ("uint16",))?, - ), - // Cast f32 to u32 - " bits_to_int_numpy::( - &bits, - elem_size, - &numpy_array.call_method1("view", ("uint32",))?, - ), - _ => Err(PyValueError::new_err(format!( - "Unsupported item type: {item_type}" - ))), - } - } - - fn set_port_numpy(&mut self, name: &str, numpy_array: &Bound<'_, PyAny>) -> PyResult<()> { - let item_type = numpy_array.getattr("dtype")?.getattr("str")?.to_string(); - let shape = self.get_port_shape(name)?; - let elem_size = shape[1]; - - let bits = match item_type.as_str() { - "|b1" => bool_numpy_to_bits(numpy_array)?, - "|u1" => int_numpy_to_bits::(numpy_array, elem_size)?, - " int_numpy_to_bits::(numpy_array, elem_size)?, - " int_numpy_to_bits::(numpy_array, elem_size)?, - " int_numpy_to_bits::(numpy_array, elem_size)?, - "|i1" => int_numpy_to_bits::(numpy_array, elem_size)?, - " int_numpy_to_bits::(numpy_array, elem_size)?, - " int_numpy_to_bits::(numpy_array, elem_size)?, - " int_numpy_to_bits::(numpy_array, elem_size)?, - // Cast to raw uint8 - " int_numpy_to_bits::(&numpy_array.call_method1("view", ("uint8",))?, elem_size)?, - // Cast f16 to u16 - " { - int_numpy_to_bits::(&numpy_array.call_method1("view", ("uint16",))?, elem_size)? - } - // Cast f32 to u32 - " { - int_numpy_to_bits::(&numpy_array.call_method1("view", ("uint32",))?, elem_size)? - } - _ => { - return Err(PyValueError::new_err(format!( - "Unsupported item type: {item_type}" - ))) - } - }; - match self.design.module.set_port_bits(name, &bits) { - Ok(()) => Ok(()), - Err(err) => Err(PyAttributeError::new_err(format!("{err}"))), - } - } -} diff --git a/crates/python_bindings/src/lib.rs b/crates/python_bindings/src/lib.rs deleted file mode 100644 index b6d63e9..0000000 --- a/crates/python_bindings/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. -// SPDX-License-Identifier: MIT - -extern crate arbolta as arbol; - -pub mod conversion; -pub mod design; - -use pyo3::prelude::*; - -#[pymodule] -fn arbolta(m: &Bound<'_, PyModule>) -> PyResult<()> { - m.add_class::()?; - - Ok(()) -} diff --git a/examples/cells/cells.v b/examples/cells/cells.v index dba5a72..a4916ec 100644 --- a/examples/cells/cells.v +++ b/examples/cells/cells.v @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT module BUF ( diff --git a/examples/designs/common/integer.sv b/examples/designs/common/integer.sv index 59cbd5a..b869915 100644 --- a/examples/designs/common/integer.sv +++ b/examples/designs/common/integer.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT // ++++++++++++++++++++ Scalar ++++++++++++++++++++ diff --git a/examples/designs/common/minifloat.sv b/examples/designs/common/minifloat.sv index f3cd3cf..1ff7e3c 100644 --- a/examples/designs/common/minifloat.sv +++ b/examples/designs/common/minifloat.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT // ++++++++++++++++++++ Scalar ++++++++++++++++++++ diff --git a/examples/designs/common/misc.sv b/examples/designs/common/misc.sv index 8893c0b..51fea08 100644 --- a/examples/designs/common/misc.sv +++ b/examples/designs/common/misc.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT module clocked_register #( diff --git a/examples/designs/common/sign_magnitude.sv b/examples/designs/common/sign_magnitude.sv index 377e4eb..22bd32e 100644 --- a/examples/designs/common/sign_magnitude.sv +++ b/examples/designs/common/sign_magnitude.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT // ++++++++++++++++++++ Scalar ++++++++++++++++++++ diff --git a/examples/designs/inexact_fma_vector_mac.sv b/examples/designs/inexact_fma_vector_mac.sv index ad76de6..17319fb 100644 --- a/examples/designs/inexact_fma_vector_mac.sv +++ b/examples/designs/inexact_fma_vector_mac.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT module fma #( diff --git a/examples/designs/int_vector_mac.sv b/examples/designs/int_vector_mac.sv index 49aaddd..65a1b85 100644 --- a/examples/designs/int_vector_mac.sv +++ b/examples/designs/int_vector_mac.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT diff --git a/examples/designs/kulisch_vector_mac.sv b/examples/designs/kulisch_vector_mac.sv index 9cdcc97..2004226 100644 --- a/examples/designs/kulisch_vector_mac.sv +++ b/examples/designs/kulisch_vector_mac.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT // Contains following designs: diff --git a/examples/designs/misc_int_vector_mac.sv b/examples/designs/misc_int_vector_mac.sv index 07ba725..94f8165 100644 --- a/examples/designs/misc_int_vector_mac.sv +++ b/examples/designs/misc_int_vector_mac.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT // Contains following designs: diff --git a/examples/designs/normalized_fma_vector_mac.sv b/examples/designs/normalized_fma_vector_mac.sv index c4e1698..dd2e41f 100644 --- a/examples/designs/normalized_fma_vector_mac.sv +++ b/examples/designs/normalized_fma_vector_mac.sv @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2024 Advanced Micro Devices, Inc. // SPDX-License-Identifier: MIT module mag_sum #( diff --git a/examples/synth.tcl b/examples/synth.tcl index 009d8d7..2c25ef1 100644 --- a/examples/synth.tcl +++ b/examples/synth.tcl @@ -1,4 +1,4 @@ -# Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +# Copyright (c) 2024 Advanced Micro Devices, Inc. # SPDX-License-Identifier: MIT yosys -import diff --git a/examples/tutorial.ipynb b/examples/tutorial.ipynb index 0a379e2..1078ca0 100644 --- a/examples/tutorial.ipynb +++ b/examples/tutorial.ipynb @@ -74,16 +74,18 @@ "from typing import TypedDict\n", "import subprocess\n", "\n", + "\n", "# Class to hold configuration for our int vector MAC\n", "class SynthConfig(TypedDict):\n", " DataWidth: int\n", " Size: int\n", " AccumulatorWidth: int\n", "\n", + "\n", "# Run synth.tcl with our parameters\n", "def run_synth(synth_config: SynthConfig) -> None:\n", " synth_params = [f\"{p_name}={p_val}\" for (p_name, p_val) in synth_config.items()]\n", - " command = ['yosys', '-c', 'synth.tcl', '--', *synth_params]\n", + " command = [\"yosys\", \"-c\", \"synth.tcl\", \"--\", *synth_params]\n", " p = subprocess.Popen(command, stdout=subprocess.PIPE)\n", " out, err = p.communicate()\n", " assert err is None" @@ -113,18 +115,14 @@ "from arbolta import HardwareDesign, DesignConfig, PortConfig\n", "\n", "DESIGN_CONFIG = DesignConfig(\n", - " clock = PortConfig(clock=True), # Don't need to specify shape\n", - " reset_i = PortConfig(reset=True), # Don't need to specify shape\n", - " op0_vec_i = PortConfig(shape=(1, 16), dtype=np.int8),\n", - " op1_vec_i = PortConfig(shape=(1, 16), dtype=np.int8),\n", - " mac_o = PortConfig(shape=(1, 1), dtype=np.int32)\n", + " clock=PortConfig(clock=True), # Don't need to specify shape\n", + " reset_i=PortConfig(reset=True), # Don't need to specify shape\n", + " op0_vec_i=PortConfig(shape=(1, 16), dtype=np.int8),\n", + " op1_vec_i=PortConfig(shape=(1, 16), dtype=np.int8),\n", + " mac_o=PortConfig(shape=(1, 1), dtype=np.int32),\n", ")\n", "\n", - "SYNTH_CONFIG = SynthConfig(\n", - " DataWidth = 8,\n", - " Size = 16,\n", - " AccumulatorWidth = 32\n", - ")\n", + "SYNTH_CONFIG = SynthConfig(DataWidth=8, Size=16, AccumulatorWidth=32)\n", "\n", "run_synth(SYNTH_CONFIG)\n", "\n", @@ -146,7 +144,7 @@ "source": [ "from graphviz_anywidget import graphviz_widget\n", "\n", - "graphviz_widget(open(\"output/schematic.dot\", 'r').read())" + "graphviz_widget(open(\"output/schematic.dot\", \"r\").read())" ] }, { @@ -187,13 +185,19 @@ "source": [ "# Extract HDL name from each nested module instance\n", "def filter_module_name(name: str) -> str:\n", - " return list(filter(lambda x: not x.startswith('$') and '=' not in x, \n", - " name.split(\"\\\\\")))[0]\n", + " return list(\n", + " filter(lambda x: not x.startswith(\"$\") and \"=\" not in x, name.split(\"\\\\\"))\n", + " )[0]\n", + "\n", "\n", "# Get area breakdown for design\n", "# Area ~= transistor count\n", - "area_df = DataFrame([{'module': filter_module_name(module), \n", - " 'area': design.area(module)} for module in design.module_names()])\n", + "area_df = DataFrame(\n", + " [\n", + " {\"module\": filter_module_name(module), \"area\": design.area(module)}\n", + " for module in design.module_names()\n", + " ]\n", + ")\n", "\n", "area_df" ] @@ -208,7 +212,7 @@ "from matplotlib import pyplot as plt\n", "\n", "# Plot area breakdown\n", - "area_df.plot(kind='barh', x='module', xlabel='Area (# of Transistors)', ylabel='')\n", + "area_df.plot(kind=\"barh\", x=\"module\", xlabel=\"Area (# of Transistors)\", ylabel=\"\")\n", "plt.tight_layout()\n", "plt.show()" ] @@ -236,20 +240,20 @@ " runs = inputs.shape[0]\n", " actual_mac = np.zeros(runs, dtype=np.int32)\n", "\n", - " design.reset() # Reset all toggle counts, signals, and flip-flops\n", + " design.reset() # Reset all toggle counts, signals, and flip-flops\n", " for i, input_pair in enumerate(inputs):\n", - " design.reset_clocked() # Reset accumulator\n", + " design.reset_clocked() # Reset accumulator\n", " design.ports.op0_vec_i = input_pair[:, 0]\n", " design.ports.op1_vec_i = input_pair[:, 1]\n", - " design.eval_clocked() # Do MAC\n", - " \n", + " design.eval_clocked() # Do MAC\n", + "\n", " actual_mac[i] = design.ports.mac_o.item()\n", "\n", " # Check correctness of design\n", - " expected_mac = (inputs[:,:,0] * inputs[:,:,1]).sum(axis=1)\n", + " expected_mac = (inputs[:, :, 0] * inputs[:, :, 1]).sum(axis=1)\n", " assert np.allclose(actual_mac, expected_mac)\n", "\n", - " return design.total_toggle_count() / runs" + " return design.total_toggle_count() / runs" ] }, { @@ -258,9 +262,9 @@ "metadata": {}, "outputs": [], "source": [ - "INT8_MIN, INT8_MAX = -128, 127 # Range of our operand datatype\n", - "VECTOR_SIZE = 16 # Size of int vector MAC\n", - "RUNS = 1000 # Number of MAC operations to average over\n", + "INT8_MIN, INT8_MAX = -128, 127 # Range of our operand datatype\n", + "VECTOR_SIZE = 16 # Size of int vector MAC\n", + "RUNS = 1000 # Number of MAC operations to average over\n", "\n", "# Generate random, uniform inputs\n", "inputs = np.random.randint(INT8_MIN, INT8_MAX + 1, (RUNS, VECTOR_SIZE, 2))\n", @@ -276,9 +280,16 @@ "outputs": [], "source": [ "# Get power breakdown per-submodule\n", - "power_df = DataFrame([{'module': filter_module_name(module), \n", - " 'toggles': design.total_toggle_count(module)} for module in design.module_names()])\n", - "power_df['toggles'] = power_df['toggles'].div(RUNS)\n", + "power_df = DataFrame(\n", + " [\n", + " {\n", + " \"module\": filter_module_name(module),\n", + " \"toggles\": design.total_toggle_count(module),\n", + " }\n", + " for module in design.module_names()\n", + " ]\n", + ")\n", + "power_df[\"toggles\"] = power_df[\"toggles\"].div(RUNS)\n", "\n", "power_df" ] @@ -290,7 +301,9 @@ "outputs": [], "source": [ "# Plot power breakdown\n", - "power_df.plot(kind='barh', x='module', xlabel='Avg. Bit-Flips per MAC Operation', ylabel='')\n", + "power_df.plot(\n", + " kind=\"barh\", x=\"module\", xlabel=\"Avg. Bit-Flips per MAC Operation\", ylabel=\"\"\n", + ")\n", "plt.tight_layout()\n", "plt.show()" ] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c8ff695 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,57 @@ +[build-system] +requires = ["maturin>=1.10,<2.0"] +build-backend = "maturin" + +[project] +name = "arbolta" +dynamic = ["version"] +description = "A hardware simulator for efficient HW/SW co-design" +authors = [ + { name = "Alexander Redding", email = "alredding@ucsd.edu" }, +] +readme = "README.md" +requires-python = ">=3.11" +license = "MIT" +license-files = ["LICENSE"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Rust", + "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", +] +dependencies = [ + "maturin>=1.10.2", + "networkx>=3.6.1", + "numpy>=2.3.5", +] + +[dependency-groups] +dev = [ + "pre-commit>=4.5.1", + "pytest>=9.0.2", + "ruff>=0.14.10", +] + +[project.urls] +Repository = "https://github.com/KastnerRG/arbolta" + +[tool.maturin] +manifest-path = "crates/arbolta_pyo3/Cargo.toml" +strip = true +python-source = "python/py_src" +exclude = [ + "python/tests/*", + "examples/*", # Shouldn't get included but just in-case +] + +[tool.uv] +package = true +cache-keys = [ + { file = "pyproject.toml" }, + { file = "Cargo.toml" }, + { file = "src/**/*.rs" }, +] diff --git a/python/py_src/arbolta/__init__.py b/python/py_src/arbolta/__init__.py new file mode 100644 index 0000000..5d2cc3e --- /dev/null +++ b/python/py_src/arbolta/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) 2026 Alexander Redding +# SPDX-License-Identifier: MIT + +from .arbolta import * # noqa:F403 diff --git a/python/py_src/arbolta/arbolta.pyi b/python/py_src/arbolta/arbolta.pyi new file mode 100644 index 0000000..3ea4d6e --- /dev/null +++ b/python/py_src/arbolta/arbolta.pyi @@ -0,0 +1,130 @@ +# Copyright (c) 2026 Alexander Redding +# SPDX-License-Identifier: MIT + +from dataclasses import dataclass +from os import PathLike +from pathlib import Path +from typing import Literal, Optional + +import numpy as np +from networkx import DiGraph +from numpy.typing import ArrayLike, DTypeLike + +@dataclass +class PortConfig: + """ + Configuration for a HardwareDesign port. + + :var shape: Interpret port bits with shape, defaults to (1, 1) + :vartype shape: tuple[int, int] + :var dtype: Interpret port bits as `dtype`, defaults to `np.uint` + :vartype dtype: DTypeLike, optional + :var clock: Port is a clock signal, defaults to None + :vartype clock: bool, optional + :var reset: Port is a reset signal, defaults to None + :vartype reset: bool, optional + :var polarity: Clock polarity of port, defaults to None + :vartype polarity: 0 | 1, optional + """ + + shape: tuple[int, int] = (1, 1) + dtype: Optional[DTypeLike] = np.uint + clock: Optional[bool] = None + reset: Optional[bool] = None + polarity: Optional[Literal[0, 1]] = None + +# TODO: Add `raises` docs +class Ports: + """ + Access to simulated module ports. Port names accessed as attributes. + """ + def __getattr__(self, name: str) -> np.ndarray: ... + def __setattr__(self, name: str, value: np.ndarray | ArrayLike) -> None: ... + + """ + Parameters + ---------- + netlist_path : str | Path | PathLike + Path to Yosys netlist JSON. + netlist_path : str | Path | PathLike + Path to Yosys topological order. + config : dict[str, PortConfig] + Configuration for design ports. + top_module : str, optional + Name of top module. + """ + +class HardwareDesign: + """ + Simulated hardware design + + :param netlist_path: Path to Yosys netlist JSON + :type netlist_path: str | Path | PathLike + :param torder_path: Path to Yosys topological order + :type torder_path: str | Path | PathLike + :param config: Configuration for design ports + :type config: dict[str, PortConfig] + :param hierarchy_separator: Additional hierarchy separator for submodules + :type hierarchy_separator: str, optional + :param top_module: Name of top module, defaults to None (find automatically) + :type top_module: str, optional + :param cell_mapping: Define additional cell types + :type cell_mapping: dict[str, tuple[str, Optional[dict[str, str]]]], optional + + :var ports: Access to simulated module ports + :vartype ports: Ports + :var modules: List of all submodules in design + :vartype modules: list[str] + """ + + ports: Ports + modules: list[str] + + def __init__( + self, + netlist_path: str | Path | PathLike, + torder_path: str | Path | PathLike, + config: dict[str, PortConfig], + hierarchy_separator: Optional[str] = None, + top_module: Optional[str] = None, + cell_mapping: Optional[dict[str, tuple[str, Optional[dict[str, str]]]]] = None, + ) -> None: ... + def reset(self) -> None: + """ + Reset all design signals and registers to zero. + Resets all toggle to zero. + """ + + def eval(self) -> None: + """ + Evaluates all cells in design. + """ + + def eval_clocked(self, cycles: Optional[int] = None) -> None: + """ + Clocks and evaluates design for `cycles`. + + :param cycles: Number of cycles to clock design, defaults to 1 + :type cycles: int, optional + + :raises AttributeError: No clock signal configured + """ + + def eval_reset_clocked(self, cycles: Optional[int] = None) -> None: + """ + Asserts reset signal and clocks design for `cycles`. + + :param cycles: Number of cycles to clock design, defaults to 1 + :type cycles: int, optional + + :raises AttributeError: No clock signal configured + :raises AttributeError: No reset signal configured + """ + + def stick_signal(self, net: int, val: Literal[0, 1]) -> None: ... + def unstick_signal(self, net: int) -> None: ... + def toggle_count( + self, category: str = "total", by_net: bool = True + ) -> dict[str, dict[str, int]] | dict[str, int]: ... + def netlist(self) -> dict: ... + def netlist_graph(self) -> DiGraph: ... diff --git a/python/tests/test_port_config.py b/python/tests/test_port_config.py new file mode 100644 index 0000000..f9efd9e --- /dev/null +++ b/python/tests/test_port_config.py @@ -0,0 +1,12 @@ +from arbolta import PortConfig + + +def test_port_config(): + x = PortConfig((1, 10), int) + + assert isinstance(x.shape, tuple) and len(x.shape) == 2 + assert x.shape[0] == 1 and x.shape[1] == 10 + assert x.dtype == int + assert isinstance(x.clock, bool) and isinstance(x.reset, bool) + assert not x.clock and not x.reset + assert x.polarity is None diff --git a/requirements/requirements_dev.txt b/requirements/requirements_dev.txt deleted file mode 100644 index 817851a..0000000 --- a/requirements/requirements_dev.txt +++ /dev/null @@ -1 +0,0 @@ -pre-commit>=4.0.1 diff --git a/requirements/requirements_examples.txt b/requirements/requirements_examples.txt deleted file mode 100644 index d18f343..0000000 --- a/requirements/requirements_examples.txt +++ /dev/null @@ -1,10 +0,0 @@ -anywidget>=0.9.13 -graphviz-anywidget>=0.3.0 -ipympl>=0.9.5 -jupyter>=1.1.1 -jupyter_client>=8.6.3 -jupyter_core>=5.7.2 -jupyterlab_widgets>=3.0.13 -matplotlib>=3.9.1.post1 -pandas>=2.2.3 -scipy>=1.14.1