Full Code of yupferris/kaze for AI

master 58c04571b2ed cached
32 files
406.4 KB
101.2k tokens
410 symbols
1 requests
Download .txt
Showing preview only (422K chars total). Download the full file or copy to clipboard to get everything.
Repository: yupferris/kaze
Branch: master
Commit: 58c04571b2ed
Files: 32
Total size: 406.4 KB

Directory structure:
gitextract_k8l9vxpv/

├── .gitignore
├── CHANGELOG.md
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── kaze/
│   ├── Cargo.toml
│   └── src/
│       ├── code_writer.rs
│       ├── graph/
│       │   ├── constant.rs
│       │   ├── context.rs
│       │   ├── internal_signal.rs
│       │   ├── mem.rs
│       │   ├── module.rs
│       │   ├── register.rs
│       │   ├── signal.rs
│       │   └── sugar.rs
│       ├── graph.rs
│       ├── lib.rs
│       ├── runtime/
│       │   ├── tracing/
│       │   │   └── vcd.rs
│       │   └── tracing.rs
│       ├── runtime.rs
│       ├── sim/
│       │   ├── compiler.rs
│       │   └── ir.rs
│       ├── sim.rs
│       ├── state_elements.rs
│       ├── validation.rs
│       ├── verilog/
│       │   ├── compiler.rs
│       │   └── ir.rs
│       └── verilog.rs
└── sim-tests/
    ├── Cargo.toml
    ├── build.rs
    └── src/
        └── lib.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
Cargo.lock
target/


================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.1.19] - 2021-03-14
### Fixed
- Bits indexing bug in verilog gen when indexing results in a scalar `Signal`

## [0.1.18] - 2020-12-13
### Fixed
- Duplicate trace member names in Rust sim gen in some cases

## [0.1.17] - 2020-12-13
### Added
- Cycle delay helpers to `Signal` API (`reg_next`, `reg_next_with_default`)

## [0.1.16] - 2020-12-13
### Fixed
- Stack overflow bugs that were still present when cloning IR expressions in the Rust sim compiler
- Broken changelog link for [0.1.15]

## [0.1.15] - 2020-12-07
### Changed
- Reduced the amount of temporary bindings used in the generated sim code, which reduces rustc compile time dramatically!
- Mark generated Rust simulator impl's with `#[automatically_derived]` to skip expensive lints during compilation

## [0.1.14] - 2020-11-29
### Changed
- Doc comments link to items by name instead of by path, as this is now supported as of [Rust 1.48.0](https://blog.rust-lang.org/2020/11/19/Rust-1.48.html).
- Dependencies updated to latest versions

### Fixed
- Stack overflow bugs by eliminating recursive graph traversals
- Invalid/outdated code in README.md
- Code formatting lints in kaze-sim-tests

## [0.1.13] - 2020-10-12
### Added
- Tracing for generated sim modules

## [0.1.12] - 2020-08-29
### Fixed
- Hack which relied on an automatically-derived `Default` impl to default-initialize most sim struct fields, which was no longer valid after `Mem` was implemented. Technically this is a breaking API change, but since `Default` was never meant to be used directly, user code shouldn't contain this.

## [0.1.11] - 2020-07-19
### Fixed
- Indexing scalars produced invalid Verilog code

## [0.1.10] - 2020-07-17
### Added
- Signed multiplication op to `Signal` API (`mul_signed`)

## [0.1.9] - 2020-07-01
### Added
- Unsigned multiplication op to `Signal` API (`mul`)

## [0.1.8] - 2020-06-28
### Fixed
- Clarified docs for `Mem` read port values when `enable` is not asserted
- Various small doc fixes/regularizations

### Changed
- Added more `if_` sugar variants for tuples with up to 12 elements (previously 8)

## [0.1.7] - 2020-03-27
### Added
- Complete Verilog codegen
- Validation tests for Verilog codegen
- `Context::modules` method to borrow a `Context`'s `Module`s, primarily useful for iterating over them for generating Verilog code

### Changed
- Simultaneous reads/writes to the same location in a `Mem` on a given cycle results in reads returning the value previously at that memory location, **not** the newly-written value

### Fixed
- Wrong publish date for 0.1.6 in changelog

## [0.1.6] - 2020-02-22
### Fixed
- Broken default value for `Mem`s with single-bit elements in generated simulators

## [0.1.5] - 2020-02-15
### Added
- `Mem` construct for creating synchronous memories

### Changed
- Internal sim compiler refactorings to simplify/unify some implementation details

### Fixed
- Missing shift doc tests

## [0.1.4] - 2020-02-09
### Fixed
- Link errors in top-level docs
- Error in `rhs_arithmetic` docs for underflow case

## [0.1.3] - 2020-02-09
### Added
- Subtraction and shift ops to `Signal` API (`sub`, `shl`, `shr`, `shr_arithmetic`)

### Changed
- Small readme edits/link fixes

### Fixed
- Module naming convention in top-level docs

## [0.1.2] - 2020-02-02
### Added
- Implement Eq/PartialEq/Hash for `Signal` (note that these are not documented/tested, which we might want to revisit later)

### Changed
- Switched naming convention for `Module`s from `snake_case` to `CamelCase`
- Redesigned entire (unstable) sugar API
- Small changelog formatting fixes

### Fixed
- Removed the last remaining `unsafe` block in the API impl

## [0.1.1] - 2020-01-30
### Added
- Signed comparison ops to `Signal` API (`lt_signed`, `le_signed`, `gt_signed`, `ge_signed`)
- Error check for `concat` to ensure its input `Signal`s belong to the same `Module`
- This changelog

### Changed
- Small typo/link fixes in API docs
- Small clarifications in top-level docs/examples
- Broken link fixes in README
- Changed tag format to be `vx.y.z` instead of `x.y.z`, and not use annotated tags

## [0.1.0] - 2020-01-25 (Initial release)

[Unreleased]: https://github.com/yupferris/kaze/compare/v0.1.19...HEAD
[0.1.19]: https://github.com/yupferris/kaze/compare/v0.1.18..v0.1.19
[0.1.18]: https://github.com/yupferris/kaze/compare/v0.1.17..v0.1.18
[0.1.17]: https://github.com/yupferris/kaze/compare/v0.1.16..v0.1.17
[0.1.16]: https://github.com/yupferris/kaze/compare/v0.1.15..v0.1.16
[0.1.15]: https://github.com/yupferris/kaze/compare/v0.1.14..v0.1.15
[0.1.14]: https://github.com/yupferris/kaze/compare/v0.1.13..v0.1.14
[0.1.13]: https://github.com/yupferris/kaze/compare/v0.1.12..v0.1.13
[0.1.12]: https://github.com/yupferris/kaze/compare/v0.1.11..v0.1.12
[0.1.11]: https://github.com/yupferris/kaze/compare/v0.1.10..v0.1.11
[0.1.10]: https://github.com/yupferris/kaze/compare/v0.1.9..v0.1.10
[0.1.9]: https://github.com/yupferris/kaze/compare/v0.1.8..v0.1.9
[0.1.8]: https://github.com/yupferris/kaze/compare/v0.1.7..v0.1.8
[0.1.7]: https://github.com/yupferris/kaze/compare/v0.1.6..v0.1.7
[0.1.6]: https://github.com/yupferris/kaze/compare/v0.1.5..v0.1.6
[0.1.5]: https://github.com/yupferris/kaze/compare/v0.1.4..v0.1.5
[0.1.4]: https://github.com/yupferris/kaze/compare/v0.1.3..v0.1.4
[0.1.3]: https://github.com/yupferris/kaze/compare/v0.1.2..v0.1.3
[0.1.2]: https://github.com/yupferris/kaze/compare/v0.1.1..v0.1.2
[0.1.1]: https://github.com/yupferris/kaze/compare/v0.1.0..v0.1.1
[0.1.0]: https://github.com/yupferris/kaze/releases/tag/v0.1.0


================================================
FILE: Cargo.toml
================================================
[workspace]

members = [
    "kaze",
    "sim-tests",
]


================================================
FILE: LICENSE-APACHE
================================================
                              Apache License
                        Version 2.0, January 2004
                     http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

   "License" shall mean the terms and conditions for use, reproduction,
   and distribution as defined by Sections 1 through 9 of this document.

   "Licensor" shall mean the copyright owner or entity authorized by
   the copyright owner that is granting the License.

   "Legal Entity" shall mean the union of the acting entity and all
   other entities that control, are controlled by, or are under common
   control with that entity. For the purposes of this definition,
   "control" means (i) the power, direct or indirect, to cause the
   direction or management of such entity, whether by contract or
   otherwise, or (ii) ownership of fifty percent (50%) or more of the
   outstanding shares, or (iii) beneficial ownership of such entity.

   "You" (or "Your") shall mean an individual or Legal Entity
   exercising permissions granted by this License.

   "Source" form shall mean the preferred form for making modifications,
   including but not limited to software source code, documentation
   source, and configuration files.

   "Object" form shall mean any form resulting from mechanical
   transformation or translation of a Source form, including but
   not limited to compiled object code, generated documentation,
   and conversions to other media types.

   "Work" shall mean the work of authorship, whether in Source or
   Object form, made available under the License, as indicated by a
   copyright notice that is included in or attached to the work
   (an example is provided in the Appendix below).

   "Derivative Works" shall mean any work, whether in Source or Object
   form, that is based on (or derived from) the Work and for which the
   editorial revisions, annotations, elaborations, or other modifications
   represent, as a whole, an original work of authorship. For the purposes
   of this License, Derivative Works shall not include works that remain
   separable from, or merely link (or bind by name) to the interfaces of,
   the Work and Derivative Works thereof.

   "Contribution" shall mean any work of authorship, including
   the original version of the Work and any modifications or additions
   to that Work or Derivative Works thereof, that is intentionally
   submitted to Licensor for inclusion in the Work by the copyright owner
   or by an individual or Legal Entity authorized to submit on behalf of
   the copyright owner. For the purposes of this definition, "submitted"
   means any form of electronic, verbal, or written communication sent
   to the Licensor or its representatives, including but not limited to
   communication on electronic mailing lists, source code control systems,
   and issue tracking systems that are managed by, or on behalf of, the
   Licensor for the purpose of discussing and improving the Work, but
   excluding communication that is conspicuously marked or otherwise
   designated in writing by the copyright owner as "Not a Contribution."

   "Contributor" shall mean Licensor and any individual or Legal Entity
   on behalf of whom a Contribution has been received by Licensor and
   subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
   this License, each Contributor hereby grants to You a perpetual,
   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
   copyright license to reproduce, prepare Derivative Works of,
   publicly display, publicly perform, sublicense, and distribute the
   Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
   this License, each Contributor hereby grants to You a perpetual,
   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
   (except as stated in this section) patent license to make, have made,
   use, offer to sell, sell, import, and otherwise transfer the Work,
   where such license applies only to those patent claims licensable
   by such Contributor that are necessarily infringed by their
   Contribution(s) alone or by combination of their Contribution(s)
   with the Work to which such Contribution(s) was submitted. If You
   institute patent litigation against any entity (including a
   cross-claim or counterclaim in a lawsuit) alleging that the Work
   or a Contribution incorporated within the Work constitutes direct
   or contributory patent infringement, then any patent licenses
   granted to You under this License for that Work shall terminate
   as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
   Work or Derivative Works thereof in any medium, with or without
   modifications, and in Source or Object form, provided that You
   meet the following conditions:

   (a) You must give any other recipients of the Work or
       Derivative Works a copy of this License; and

   (b) You must cause any modified files to carry prominent notices
       stating that You changed the files; and

   (c) You must retain, in the Source form of any Derivative Works
       that You distribute, all copyright, patent, trademark, and
       attribution notices from the Source form of the Work,
       excluding those notices that do not pertain to any part of
       the Derivative Works; and

   (d) If the Work includes a "NOTICE" text file as part of its
       distribution, then any Derivative Works that You distribute must
       include a readable copy of the attribution notices contained
       within such NOTICE file, excluding those notices that do not
       pertain to any part of the Derivative Works, in at least one
       of the following places: within a NOTICE text file distributed
       as part of the Derivative Works; within the Source form or
       documentation, if provided along with the Derivative Works; or,
       within a display generated by the Derivative Works, if and
       wherever such third-party notices normally appear. The contents
       of the NOTICE file are for informational purposes only and
       do not modify the License. You may add Your own attribution
       notices within Derivative Works that You distribute, alongside
       or as an addendum to the NOTICE text from the Work, provided
       that such additional attribution notices cannot be construed
       as modifying the License.

   You may add Your own copyright statement to Your modifications and
   may provide additional or different license terms and conditions
   for use, reproduction, or distribution of Your modifications, or
   for any such Derivative Works as a whole, provided Your use,
   reproduction, and distribution of the Work otherwise complies with
   the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
   any Contribution intentionally submitted for inclusion in the Work
   by You to the Licensor shall be under the terms and conditions of
   this License, without any additional terms or conditions.
   Notwithstanding the above, nothing herein shall supersede or modify
   the terms of any separate license agreement you may have executed
   with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
   names, trademarks, service marks, or product names of the Licensor,
   except as required for reasonable and customary use in describing the
   origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
   agreed to in writing, Licensor provides the Work (and each
   Contributor provides its Contributions) on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   implied, including, without limitation, any warranties or conditions
   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
   PARTICULAR PURPOSE. You are solely responsible for determining the
   appropriateness of using or redistributing the Work and assume any
   risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
   whether in tort (including negligence), contract, or otherwise,
   unless required by applicable law (such as deliberate and grossly
   negligent acts) or agreed to in writing, shall any Contributor be
   liable to You for damages, including any direct, indirect, special,
   incidental, or consequential damages of any character arising as a
   result of this License or out of the use or inability to use the
   Work (including but not limited to damages for loss of goodwill,
   work stoppage, computer failure or malfunction, or any and all
   other commercial damages or losses), even if such Contributor
   has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
   the Work or Derivative Works thereof, You may choose to offer,
   and charge a fee for, acceptance of support, warranty, indemnity,
   or other liability obligations and/or rights consistent with this
   License. However, in accepting such obligations, You may act only
   on Your own behalf and on Your sole responsibility, not on behalf
   of any other Contributor, and only if You agree to indemnify,
   defend, and hold each Contributor harmless for any liability
   incurred by, or claims asserted against, such Contributor by reason
   of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

   To apply the Apache License to your work, attach the following
   boilerplate notice, with the fields enclosed by brackets "[]"
   replaced with your own identifying information. (Don't include
   the brackets!)  The text should be enclosed in the appropriate
   comment syntax for the file format. We also recommend that a
   file or class name and description of purpose be included on the
   same "printed page" as the copyright notice for easier
   identification within third-party archives.

Copyright 2019-2021 Jake "ferris" Taylor

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: LICENSE-MIT
================================================
Copyright (c) 2019-2021 Jake "ferris" Taylor

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
# kaze [風](https://jisho.org/search/%E9%A2%A8%20%23kanji)

An [HDL](https://en.wikipedia.org/wiki/Hardware_description_language) embedded in [Rust](https://www.rust-lang.org/).

[<img alt="github" src="https://img.shields.io/badge/github-yupferris/kaze-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/yupferris/kaze)
[<img alt="crates.io" src="https://img.shields.io/crates/v/kaze.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/kaze)
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-kaze-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/kaze)
[<img alt="license" src="https://img.shields.io/crates/l/kaze?style=for-the-badge" height="20">](#license)

kaze provides an API to describe `Module`s composed of `Signal`s, which can then be used to generate Rust simulator code or Verilog modules.

kaze's API is designed to be as minimal as possible while still being expressive.
It's designed to prevent the user from being able to describe buggy or incorrect hardware as much as possible.
This enables a user to hack on designs fearlessly, while the API and generators ensure that these designs are sound.

## Usage

```toml
[dependencies]
kaze = "0.1"
```

## Example

```rust
use kaze::*;

fn main() -> std::io::Result<()> {
    // Create a context, which will contain our module(s)
    let c = Context::new();

    // Create a module
    let inverter = c.module("Inverter");
    let i = inverter.input("i", 1); // 1-bit input
    inverter.output("o", !i); // Output inverted input

    // Generate Rust simulator code
    sim::generate(inverter, sim::GenerationOptions::default(), std::io::stdout())?;

    // Generate Verilog code
    verilog::generate(inverter, std::io::stdout())?;

    Ok(())
}
```

## Releases

See [changelog](https://github.com/yupferris/kaze/blob/master/CHANGELOG.md) for release information.

## License

Licensed under either of

 * Apache License, Version 2.0
   ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license
   ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

## Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.


================================================
FILE: kaze/Cargo.toml
================================================
[package]
name = "kaze"
version = "0.1.19" # Must be kept up-to-date with html_root_url in lib.rs
authors = ["Jake \"ferris\" Taylor <yupferris@gmail.com>"]
edition = "2018"
description = "An HDL embedded in Rust"
license = "MIT OR Apache-2.0"
repository = "https://github.com/yupferris/kaze"
readme = "../README.md"
keywords = ["hdl"]
categories = ["development-tools", "emulators", "simulation"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
typed-arena = "2.0.1"
vcd = "0.6.1"


================================================
FILE: kaze/src/code_writer.rs
================================================
use std::io::{Result, Write};

pub struct CodeWriter<W: Write> {
    w: W,
    indent_level: u32,
}

impl<W: Write> CodeWriter<W> {
    pub fn new(w: W) -> CodeWriter<W> {
        CodeWriter { w, indent_level: 0 }
    }

    pub fn indent(&mut self) {
        self.indent_level += 1;
    }

    pub fn unindent(&mut self) {
        if self.indent_level == 0 {
            panic!("Indent level underflow");
        }
        self.indent_level -= 1;
    }

    pub fn append_indent(&mut self) -> Result<()> {
        for _ in 0..self.indent_level {
            write!(self.w, "    ")?;
        }
        Ok(())
    }

    pub fn append_newline(&mut self) -> Result<()> {
        writeln!(self.w, "")?;
        Ok(())
    }

    pub fn append(&mut self, s: &str) -> Result<()> {
        write!(self.w, "{}", s)?;
        Ok(())
    }

    pub fn append_line(&mut self, s: &str) -> Result<()> {
        self.append_indent()?;
        self.append(s)?;
        self.append_newline()?;
        Ok(())
    }
}


================================================
FILE: kaze/src/graph/constant.rs
================================================
/// A container for different types of integer constant values.
///
/// This type isn't typically used explicitly, as the graph API always takes `Constant` parameters as `Into<Constant>`, and `Constant` implements `From` for most of Rust's unsigned integer types. If an API entry point requires a `Constant`, prefer passing integer values/literals directly.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let p = Context::new();
///
/// let m = p.module("m", "MyModule");
///
/// let a = m.lit(true, 16);
/// let b = m.lit(0xdeadbeefu32, 47);
/// let c = m.reg("data", 20);
/// c.default_value(5u32);
/// let d = m.lit(42u32, 8);
/// ```
#[derive(Clone)]
pub enum Constant {
    /// Contains a boolean value
    Bool(bool),
    /// Contains an unsigned, 32-bit value
    U32(u32),
    /// Contains an unsigned, 64-bit value
    U64(u64),
    /// Contains an unsigned, 128-bit value
    U128(u128),
}

impl Constant {
    // TODO: Specific tests? I don't necessarily want to make this part of the public API at least.
    pub(super) fn required_bits(&self) -> u32 {
        match *self {
            Constant::Bool(value) => 32 - (value as u32).leading_zeros(),
            Constant::U32(value) => 32 - value.leading_zeros(),
            Constant::U64(value) => 64 - value.leading_zeros(),
            Constant::U128(value) => 128 - value.leading_zeros(),
        }
    }

    pub(crate) fn numeric_value(&self) -> u128 {
        match *self {
            Constant::Bool(value) => value.into(),
            Constant::U32(value) => value.into(),
            Constant::U64(value) => value.into(),
            Constant::U128(value) => value,
        }
    }
}

impl From<bool> for Constant {
    fn from(value: bool) -> Self {
        Constant::Bool(value)
    }
}

impl From<u8> for Constant {
    fn from(value: u8) -> Self {
        Constant::U32(value as _)
    }
}

impl From<u16> for Constant {
    fn from(value: u16) -> Self {
        Constant::U32(value as _)
    }
}

impl From<u32> for Constant {
    fn from(value: u32) -> Self {
        Constant::U32(value)
    }
}

impl From<u64> for Constant {
    fn from(value: u64) -> Self {
        Constant::U64(value)
    }
}

impl From<u128> for Constant {
    fn from(value: u128) -> Self {
        Constant::U128(value)
    }
}


================================================
FILE: kaze/src/graph/context.rs
================================================
use super::internal_signal::*;
use super::mem::*;
use super::module::*;
use super::register::*;

use typed_arena::Arena;

use std::cell::RefCell;

// TODO: Move, doc
pub trait ModuleParent<'a> {
    // TODO: Update doc
    /// Creates a new [`Module`] called `name` in this `Context`.
    ///
    /// Conventionally, `name` should be `CamelCase`, though this is not enforced.
    ///
    /// # Panics
    ///
    /// Panics if a [`Module`] with the same `name` already exists in this `Context`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let my_module = c.module("my_module", "MyModule");
    /// let another_mod = c.module("another_mod", "AnotherMod");
    /// ```
    ///
    /// The following example panics by creating a `Module` with the same `name` as a previously-created `Module` in the same `Context`:
    ///
    /// ```should_panic
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let _ = c.module("a", "A"); // Unique name, OK
    /// let _ = c.module("b", "B"); // Unique name, OK
    ///
    /// let _ = c.module("a", "A"); // Non-unique name, panic!
    /// ```
    fn module(&'a self, instance_name: impl Into<String>, name: impl Into<String>) -> &Module;
}

/// A top-level container/owner object for a [`Module`] graph.
///
/// A `Context` owns all parts of a module graph, and provides an API for creating [`Module`] objects.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("m", "MyModule");
/// m.output("out", m.input("in", 1));
/// ```
#[must_use]
pub struct Context<'a> {
    pub(super) module_arena: Arena<Module<'a>>,
    pub(super) input_data_arena: Arena<InputData<'a>>,
    pub(super) input_arena: Arena<Input<'a>>,
    pub(super) output_data_arena: Arena<OutputData<'a>>,
    pub(super) output_arena: Arena<Output<'a>>,
    pub(super) signal_arena: Arena<InternalSignal<'a>>,
    pub(super) register_data_arena: Arena<RegisterData<'a>>,
    pub(super) register_arena: Arena<Register<'a>>,
    pub(super) mem_arena: Arena<Mem<'a>>,

    pub(super) modules: RefCell<Vec<&'a Module<'a>>>,
}

impl<'a> Context<'a> {
    /// Creates a new, empty `Context`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    /// ```
    pub fn new() -> Context<'a> {
        Context {
            module_arena: Arena::new(),
            input_data_arena: Arena::new(),
            input_arena: Arena::new(),
            output_data_arena: Arena::new(),
            output_arena: Arena::new(),
            signal_arena: Arena::new(),
            register_data_arena: Arena::new(),
            register_arena: Arena::new(),
            mem_arena: Arena::new(),

            modules: RefCell::new(Vec::new()),
        }
    }
}

impl<'a> ModuleParent<'a> for Context<'a> {
    // TODO: Docs, error handling
    fn module(&'a self, instance_name: impl Into<String>, name: impl Into<String>) -> &Module {
        let instance_name = instance_name.into();
        let name = name.into();
        let module = self
            .module_arena
            .alloc(Module::new(self, None, instance_name, name));
        self.modules.borrow_mut().push(module);
        module
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn new_context_has_no_modules() {
        let c = Context::new();

        assert!(c.modules.borrow().is_empty());
    }
}


================================================
FILE: kaze/src/graph/internal_signal.rs
================================================
use super::constant::*;
use super::context::*;
use super::mem::*;
use super::module::*;
use super::register::*;

use std::hash::{Hash, Hasher};
use std::ptr;

pub struct InternalSignal<'a> {
    pub(super) context: &'a Context<'a>,
    pub(crate) module: &'a Module<'a>,

    pub(crate) data: SignalData<'a>,
}

impl<'a> InternalSignal<'a> {
    pub fn bit_width(&'a self) -> u32 {
        match self.data {
            SignalData::Lit { bit_width, .. } => bit_width,
            SignalData::Input { data } => data.bit_width,
            // TODO: Test above
            SignalData::Output { data } => data.bit_width,
            SignalData::Reg { data } => data.bit_width,
            SignalData::UnOp { bit_width, .. } => bit_width,
            SignalData::SimpleBinOp { bit_width, .. } => bit_width,
            SignalData::AdditiveBinOp { bit_width, .. } => bit_width,
            SignalData::ComparisonBinOp { .. } => 1,
            SignalData::ShiftBinOp { bit_width, .. } => bit_width,
            SignalData::Mul { bit_width, .. } => bit_width,
            SignalData::MulSigned { bit_width, .. } => bit_width,
            SignalData::Bits {
                range_high,
                range_low,
                ..
            } => range_high - range_low + 1,
            SignalData::Repeat { bit_width, .. } => bit_width,
            SignalData::Concat { bit_width, .. } => bit_width,
            SignalData::Mux { bit_width, .. } => bit_width,
            SignalData::MemReadPortOutput { mem, .. } => mem.element_bit_width,
        }
    }

    pub(crate) fn module_instance_name_prefix(&self) -> String {
        let mut stack = Vec::new();
        let mut module = Some(self.module);
        while let Some(m) = module {
            stack.push(m);
            module = m.parent;
        }

        let mut ret = String::new();
        while let Some(m) = stack.pop() {
            ret = if ret.is_empty() {
                m.instance_name.clone()
            } else {
                format!("{}_{}", ret, m.instance_name)
            };
        }

        ret
    }
}

impl<'a> Eq for &'a InternalSignal<'a> {}

impl<'a> Hash for &'a InternalSignal<'a> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_usize(*self as *const _ as usize)
    }
}

impl<'a> PartialEq for &'a InternalSignal<'a> {
    fn eq(&self, other: &Self) -> bool {
        ptr::eq(*self, *other)
    }
}

pub(crate) enum SignalData<'a> {
    Lit {
        value: Constant,
        bit_width: u32,
    },

    Input {
        data: &'a InputData<'a>,
    },
    Output {
        data: &'a OutputData<'a>,
    },

    // TODO: Rename to Register?
    Reg {
        data: &'a RegisterData<'a>,
    },

    UnOp {
        source: &'a InternalSignal<'a>,
        op: UnOp,
        bit_width: u32,
    },
    SimpleBinOp {
        lhs: &'a InternalSignal<'a>,
        rhs: &'a InternalSignal<'a>,
        op: SimpleBinOp,
        bit_width: u32,
    },
    AdditiveBinOp {
        lhs: &'a InternalSignal<'a>,
        rhs: &'a InternalSignal<'a>,
        op: AdditiveBinOp,
        bit_width: u32,
    },
    ComparisonBinOp {
        lhs: &'a InternalSignal<'a>,
        rhs: &'a InternalSignal<'a>,
        op: ComparisonBinOp,
    },
    ShiftBinOp {
        lhs: &'a InternalSignal<'a>,
        rhs: &'a InternalSignal<'a>,
        op: ShiftBinOp,
        bit_width: u32,
    },

    Mul {
        lhs: &'a InternalSignal<'a>,
        rhs: &'a InternalSignal<'a>,
        bit_width: u32,
    },
    MulSigned {
        lhs: &'a InternalSignal<'a>,
        rhs: &'a InternalSignal<'a>,
        bit_width: u32,
    },

    Bits {
        source: &'a InternalSignal<'a>,
        range_high: u32,
        range_low: u32,
    },

    Repeat {
        source: &'a InternalSignal<'a>,
        count: u32,
        bit_width: u32,
    },
    Concat {
        lhs: &'a InternalSignal<'a>,
        rhs: &'a InternalSignal<'a>,
        bit_width: u32,
    },

    Mux {
        cond: &'a InternalSignal<'a>,
        when_true: &'a InternalSignal<'a>,
        when_false: &'a InternalSignal<'a>,
        bit_width: u32,
    },

    MemReadPortOutput {
        mem: &'a Mem<'a>,
        address: &'a InternalSignal<'a>,
        enable: &'a InternalSignal<'a>,
    },
}

#[derive(Clone, Copy)]
pub(crate) enum UnOp {
    Not,
}

#[derive(Clone, Copy)]
pub(crate) enum SimpleBinOp {
    BitAnd,
    BitOr,
    BitXor,
}

#[derive(Clone, Copy)]
pub(crate) enum ComparisonBinOp {
    Equal,
    GreaterThan,
    GreaterThanEqual,
    GreaterThanEqualSigned,
    GreaterThanSigned,
    LessThan,
    LessThanEqual,
    LessThanEqualSigned,
    LessThanSigned,
    NotEqual,
}

#[derive(Clone, Copy)]
pub(crate) enum AdditiveBinOp {
    Add,
    Sub,
}

#[derive(Clone, Copy)]
pub(crate) enum ShiftBinOp {
    Shl,
    Shr,
    ShrArithmetic,
}

pub trait GetInternalSignal<'a> {
    // TODO: Rename to `get_internal_signal` ?
    fn internal_signal(&'a self) -> &'a InternalSignal<'a>;
}

impl<'a> GetInternalSignal<'a> for InternalSignal<'a> {
    fn internal_signal(&'a self) -> &'a InternalSignal<'a> {
        self
    }
}


================================================
FILE: kaze/src/graph/mem.rs
================================================
use super::constant::*;
use super::context::*;
use super::internal_signal::*;
use super::module::*;
use super::signal::*;

use std::cell::RefCell;
use std::hash::{Hash, Hasher};
use std::ptr;

/// A synchronous memory, created by the [`Module::mem`] method.
///
/// Memories in kaze are always sequential/synchronous-read, sequential/synchronous-write memories.
/// This means that when a read and/or write is asserted, the read/write will be visible on the cycle immediately following the cycle in which it's asserted.
/// If both a write and a read to the same location occurs within the same cycle, the read will return the previous value at the memory location, **not** the newly-written value.
///
/// Memories must have at least one read port specified.
/// Multiple reads to the same location within the same cycle will return the same value.
///
/// Memories may optionally have initial contents and/or a write port specified.
/// If either of these are missing, the contents of the memory can't be determined, so this is a logical error.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("m", "MyModule");
///
/// let my_mem = m.mem("my_mem", 1, 32);
/// // Optional, unless no write port is specified
/// my_mem.initial_contents(&[0xfadebabeu32, 0xdeadbeefu32]);
/// // Optional, unless no initial contents are specified
/// my_mem.write_port(m.high(), m.lit(0xabad1deau32, 32), m.high());
/// m.output("my_output", my_mem.read_port(m.high(), m.high()));
/// ```
#[must_use]
pub struct Mem<'a> {
    pub(super) context: &'a Context<'a>,
    pub(crate) module: &'a Module<'a>,

    pub(crate) name: String,
    pub(crate) address_bit_width: u32,
    pub(crate) element_bit_width: u32,

    pub(crate) initial_contents: RefCell<Option<Vec<Constant>>>,

    pub(crate) read_ports: RefCell<Vec<(&'a InternalSignal<'a>, &'a InternalSignal<'a>)>>,
    pub(crate) write_port: RefCell<
        Option<(
            &'a InternalSignal<'a>,
            &'a InternalSignal<'a>,
            &'a InternalSignal<'a>,
        )>,
    >,
}

impl<'a> Mem<'a> {
    /// Specifies the initial contents for this `Mem`.
    ///
    /// Reads from this `Mem` will reflect the values specified unless writes have overwritten them (if the `Mem` has a write port).
    ///
    /// By default, a `Mem` does not have initial contents, and it is not required to specify them unless the `Mem` does not have a write port.
    /// If initial contents are not specified, then this `Mem`'s contents will be undefined initially.
    ///
    /// Note that these contents are **not** restored when the containing [`Module`]'s implicit reset is asserted.
    ///
    /// # Panics
    ///
    /// Panics if this `Mem` already has initial contents specified, if `contents.len()` doesn't match the number of elements in this `Mem`, or if any of the specified element values don't fit into this `Mem`'s element bit width.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let my_mem = m.mem("my_mem", 1, 32);
    /// // Optional, unless no write port is specified
    /// my_mem.initial_contents(&[0xfadebabeu32, 0xdeadbeefu32]);
    /// // Optional, unless no initial contents are specified
    /// my_mem.write_port(m.high(), m.lit(0xabad1deau32, 32), m.high());
    /// m.output("my_output", my_mem.read_port(m.high(), m.high()));
    /// ```
    pub fn initial_contents<C: Clone + Into<Constant>>(&'a self, contents: &[C]) {
        if self.initial_contents.borrow().is_some() {
            panic!("Attempted to specify initial contents for memory \"{}\" in module \"{}\", but this memory already has initial contents.", self.name, self.module.name);
        }
        let expected_contents_len = 1 << self.address_bit_width;
        if contents.len() != expected_contents_len {
            panic!("Attempted to specify initial contents for memory \"{}\" in module \"{}\" that contains {} element(s), but this memory has {} address bit(s), and requires {} element(s).", self.name, self.module.name, contents.len(), self.address_bit_width, expected_contents_len);
        }
        *self.initial_contents.borrow_mut() = Some(contents.iter().cloned().enumerate().map(|(i, x)| {
            let ret = x.into();
            if ret.required_bits() > self.element_bit_width {
                panic!("Attempted to specify initial contents for memory \"{}\" in module \"{}\", but this memory has an element width of {} bit(s), and these initial contents specify element {} with value {} which requires {} bit(s).", self.name, self.module.name, self.element_bit_width, i, ret.numeric_value(), ret.required_bits());
            }
            ret
        }).collect());
    }

    /// Specifies a read port for this `Mem` and returns a [`Signal`] representing the data read from this port.
    ///
    /// `Mem`s are required to have at least one read port, otherwise the memory contents could never be read, which would be a logical error.
    /// There is no upper bound to the number of read ports specified in kaze, however a target device may not be able to synthesize the resulting Verilog code if too many are used.
    ///
    /// Read ports always have an `address` signal and an `enable` signal.
    /// When `enable` is asserted, the returned [`Signal`] will reflect the data read from the location specified by `address` on the following cycle.
    /// If `enable` is not asserted, then the value of the returned [`Signal`] is unchanged on the following cycle and reflects the value of the most recent read (note that this may be undefined before a valid read has occurred).
    ///
    /// # Panics
    ///
    /// Panics if `address`'s bit width doesn't match this `Mem`'s address bit width, or if `enable`'s bit width is not `1`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let my_mem = m.mem("my_mem", 1, 32);
    /// // Optional, unless no write port is specified
    /// my_mem.initial_contents(&[0xfadebabeu32, 0xdeadbeefu32]);
    /// // Optional, unless no initial contents are specified
    /// my_mem.write_port(m.high(), m.lit(0xabad1deau32, 32), m.high());
    /// m.output("my_output", my_mem.read_port(m.high(), m.high()));
    /// ```
    pub fn read_port(
        &'a self,
        address: &'a dyn Signal<'a>,
        enable: &'a dyn Signal<'a>,
    ) -> &dyn Signal<'a> {
        let address = address.internal_signal();
        let enable = enable.internal_signal();
        // TODO: Limit amount of read ports added?
        if address.bit_width() != self.address_bit_width {
            panic!("Attempted to specify a read port for memory \"{}\" in module \"{}\" with an address signal with {} bit(s), but this memory has {} address bit(s).", self.name, self.module.name, address.bit_width(), self.address_bit_width);
        }
        if enable.bit_width() != 1 {
            panic!("Attempted to specify a read port for memory \"{}\" in module \"{}\" with an enable signal with {} bit(s), but memory read/write ports are required to be 1 bit wide.", self.name, self.module.name, enable.bit_width());
        }
        let ret = self.context.signal_arena.alloc(InternalSignal {
            context: self.context,
            module: self.module,

            data: SignalData::MemReadPortOutput {
                mem: self,
                address,
                enable,
            },
        });
        self.read_ports.borrow_mut().push((address, enable));
        ret
    }

    /// Specifies a write port for this `Mem`.
    ///
    /// By default, a `Mem` does not have any write ports, and it is not required to specify one unless the `Mem` does not have initial contents.
    ///
    /// Write ports always have an `address` signal, a `value` signal, and an `enable` signal.
    /// When `enable` is asserted, the value at the location specified by `address` will reflect the value of the `value` signal on the following cycle.
    /// If `enable` is not asserted, then the memory contents will not change.
    ///
    /// # Panics
    ///
    /// Panics if this `Mem` already has a write port specified, if `address`'s bit width doesn't match this `Mem`'s address bit width, if `value`'s bit width doesn't match this `Mem`'s element bit width, or if `enable`'s bit width is not `1`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let my_mem = m.mem("my_mem", 1, 32);
    /// // Optional, unless no write port is specified
    /// my_mem.initial_contents(&[0xfadebabeu32, 0xdeadbeefu32]);
    /// // Optional, unless no initial contents are specified
    /// my_mem.write_port(m.high(), m.lit(0xabad1deau32, 32), m.high());
    /// m.output("my_output", my_mem.read_port(m.high(), m.high()));
    /// ```
    // TODO: byte/word enable? How might that interface look?
    pub fn write_port(
        &'a self,
        address: &'a dyn Signal<'a>,
        value: &'a dyn Signal<'a>,
        enable: &'a dyn Signal<'a>,
    ) {
        let address = address.internal_signal();
        let value = value.internal_signal();
        let enable = enable.internal_signal();
        if self.write_port.borrow().is_some() {
            panic!("Attempted to specify a write port for memory \"{}\" in module \"{}\", but this memory already has a write port.", self.name, self.module.name);
        }
        if address.bit_width() != self.address_bit_width {
            panic!("Attempted to specify a write port for memory \"{}\" in module \"{}\" with an address signal with {} bit(s), but this memory has {} address bit(s).", self.name, self.module.name, address.bit_width(), self.address_bit_width);
        }
        if value.bit_width() != self.element_bit_width {
            panic!("Attempted to specify a write port for memory \"{}\" in module \"{}\" with a value signal with {} bit(s), but this memory has {} element bit(s).", self.name, self.module.name, value.bit_width(), self.element_bit_width);
        }
        if enable.bit_width() != 1 {
            panic!("Attempted to specify a write port for memory \"{}\" in module \"{}\" with an enable signal with {} bit(s), but memory read/write ports are required to be 1 bit wide.", self.name, self.module.name, enable.bit_width());
        }
        *self.write_port.borrow_mut() = Some((address, value, enable));
    }
}

impl<'a> Eq for &'a Mem<'a> {}

impl<'a> Hash for &'a Mem<'a> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_usize(*self as *const _ as usize)
    }
}

impl<'a> PartialEq for &'a Mem<'a> {
    fn eq(&self, other: &Self) -> bool {
        ptr::eq(*self, *other)
    }
}

#[cfg(test)]
mod tests {
    use crate::*;

    #[test]
    #[should_panic(
        expected = "Attempted to specify initial contents for memory \"mem\" in module \"A\", but this memory already has initial contents."
    )]
    fn initial_contents_already_specified_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let mem = m.mem("mem", 1, 1);

        mem.initial_contents(&[true, false]);

        // Panic
        mem.initial_contents(&[true, false]);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to specify initial contents for memory \"mem\" in module \"A\" that contains 3 element(s), but this memory has 1 address bit(s), and requires 2 element(s)."
    )]
    fn initial_contents_length_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let mem = m.mem("mem", 1, 1);

        // Panic
        mem.initial_contents(&[true, false, true]);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to specify initial contents for memory \"mem\" in module \"A\", but this memory has an element width of 1 bit(s), and these initial contents specify element 0 with value 2 which requires 2 bit(s)."
    )]
    fn initial_contents_element_bit_width_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let mem = m.mem("mem", 1, 1);

        // Panic
        mem.initial_contents(&[2u32, 0u32]);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to specify a read port for memory \"mem\" in module \"A\" with an address signal with 2 bit(s), but this memory has 1 address bit(s)."
    )]
    fn read_port_address_bit_width_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let mem = m.mem("mem", 1, 1);

        // Panic
        let _ = mem.read_port(m.lit(0u32, 2), m.low());
    }

    #[test]
    #[should_panic(
        expected = "Attempted to specify a read port for memory \"mem\" in module \"A\" with an enable signal with 2 bit(s), but memory read/write ports are required to be 1 bit wide."
    )]
    fn read_port_enable_bit_width_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let mem = m.mem("mem", 1, 1);

        // Panic
        let _ = mem.read_port(m.low(), m.lit(0u32, 2));
    }

    #[test]
    #[should_panic(
        expected = "Attempted to specify a write port for memory \"mem\" in module \"A\", but this memory already has a write port."
    )]
    fn write_port_already_specified_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let mem = m.mem("mem", 1, 1);

        mem.write_port(m.low(), m.low(), m.low());

        // Panic
        mem.write_port(m.low(), m.low(), m.low());
    }

    #[test]
    #[should_panic(
        expected = "Attempted to specify a write port for memory \"mem\" in module \"A\" with an address signal with 2 bit(s), but this memory has 1 address bit(s)."
    )]
    fn write_port_address_bit_width_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let mem = m.mem("mem", 1, 1);

        // Panic
        mem.write_port(m.lit(0u32, 2), m.low(), m.low());
    }

    #[test]
    #[should_panic(
        expected = "Attempted to specify a write port for memory \"mem\" in module \"A\" with a value signal with 2 bit(s), but this memory has 1 element bit(s)."
    )]
    fn write_port_value_bit_width_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let mem = m.mem("mem", 1, 1);

        // Panic
        mem.write_port(m.low(), m.lit(0u32, 2), m.low());
    }

    #[test]
    #[should_panic(
        expected = "Attempted to specify a write port for memory \"mem\" in module \"A\" with an enable signal with 2 bit(s), but memory read/write ports are required to be 1 bit wide."
    )]
    fn write_port_enable_bit_width_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let mem = m.mem("mem", 1, 1);

        // Panic
        mem.write_port(m.low(), m.low(), m.lit(0u32, 2));
    }
}


================================================
FILE: kaze/src/graph/module.rs
================================================
use super::constant::*;
use super::context::*;
use super::internal_signal::*;
use super::mem::*;
use super::register::*;
use super::signal::*;

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};
use std::ptr;

/// A self-contained and potentially-reusable hardware design unit, created by the [`Context::module`] method.
///
/// Once a `Module` is specified, it can be [instantiated](Self::instance) in another `Module` to form a hierarchy, or it can be used to generate [Rust simulator code](crate::sim::generate) or a [Verilog module](crate::verilog::generate).
///
/// All `Module`s in kaze have an implicit reset and clock. These are only visible in generated code. It's assumed that all kaze modules operate in the same clock domain.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("m", "MyModule");
/// m.output("out", m.input("in", 1));
/// ```
// TODO: Validation error if a module has no inputs/outputs
// TODO: Document composing modules (even if it's really basic)
#[must_use]
pub struct Module<'a> {
    context: &'a Context<'a>,

    pub(crate) parent: Option<&'a Module<'a>>,

    pub(crate) instance_name: String,
    pub(crate) name: String,

    // TODO: Do we need to duplicate the input/output names here?
    pub(crate) inputs: RefCell<BTreeMap<String, &'a Input<'a>>>,
    pub(crate) outputs: RefCell<BTreeMap<String, &'a Output<'a>>>,
    pub(crate) registers: RefCell<Vec<&'a InternalSignal<'a>>>,
    pub(crate) modules: RefCell<Vec<&'a Module<'a>>>,
    pub(crate) mems: RefCell<Vec<&'a Mem<'a>>>,
}

impl<'a> Module<'a> {
    pub(super) fn new(
        context: &'a Context<'a>,
        parent: Option<&'a Module<'a>>,
        instance_name: String,
        name: String,
    ) -> Module<'a> {
        Module {
            context,

            parent,

            instance_name,
            name,

            inputs: RefCell::new(BTreeMap::new()),
            outputs: RefCell::new(BTreeMap::new()),
            registers: RefCell::new(Vec::new()),
            modules: RefCell::new(Vec::new()),
            mems: RefCell::new(Vec::new()),
        }
    }

    /// Creates a [`Signal`] that represents the constant literal specified by `value` with `bit_width` bits.
    ///
    /// The bit width of the type provided by `value` doesn't need to match `bit_width`, but the value represented by `value` must fit into `bit_width` bits.
    ///
    /// # Panics
    ///
    /// Panics if `bit_width` is less than [`MIN_SIGNAL_BIT_WIDTH`] or greater than [`MAX_SIGNAL_BIT_WIDTH`], respectively, or if the specified `value` doesn't fit into `bit_width` bits.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let eight_bit_const = m.lit(0xffu32, 8);
    /// let one_bit_const = m.lit(0u32, 1);
    /// let twenty_seven_bit_const = m.lit(true, 27);
    /// ```
    pub fn lit(&'a self, value: impl Into<Constant>, bit_width: u32) -> &dyn Signal<'a> {
        if bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a literal with {} bit(s). Signals must not be narrower than {} bit(s).",
                bit_width, MIN_SIGNAL_BIT_WIDTH
            );
        }
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a literal with {} bit(s). Signals must not be wider than {} bit(s).",
                bit_width, MAX_SIGNAL_BIT_WIDTH
            );
        }
        let value = value.into();
        let required_bits = value.required_bits();
        if required_bits > bit_width {
            let numeric_value = value.numeric_value();
            panic!("Cannot fit the specified value '{}' into the specified bit width '{}'. The value '{}' requires a bit width of at least {} bit(s).", numeric_value, bit_width, numeric_value, required_bits);
        }
        self.context.signal_arena.alloc(InternalSignal {
            context: self.context,
            module: self,

            data: SignalData::Lit { value, bit_width },
        })
    }

    /// Convenience method to create a [`Signal`] that represents a single `0` bit.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// // The following two signals are semantically equivalent:
    /// let low1 = m.low();
    /// let low2 = m.lit(false, 1);
    /// ```
    pub fn low(&'a self) -> &dyn Signal<'a> {
        self.lit(false, 1)
    }

    /// Convenience method to create a [`Signal`] that represents a single `1` bit.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// // The following two signals are semantically equivalent:
    /// let high1 = m.high();
    /// let high2 = m.lit(true, 1);
    /// ```
    pub fn high(&'a self) -> &dyn Signal<'a> {
        self.lit(true, 1)
    }

    /// Creates an input for this `Module` called `name` with `bit_width` bits, and returns a [`Signal`] that represents the value of this input.
    ///
    /// # Panics
    ///
    /// Panics if `bit_width` is less than [`MIN_SIGNAL_BIT_WIDTH`] or greater than [`MAX_SIGNAL_BIT_WIDTH`], respectively.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let my_input = m.input("my_input", 80);
    /// ```
    pub fn input(&'a self, name: impl Into<String>, bit_width: u32) -> &Input<'a> {
        let name = name.into();
        // TODO: Error if name already exists in this context
        if bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create an input with {} bit(s). Signals must not be narrower than {} bit(s).",
                bit_width, MIN_SIGNAL_BIT_WIDTH
            );
        }
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create an input with {} bit(s). Signals must not be wider than {} bit(s).",
                bit_width, MAX_SIGNAL_BIT_WIDTH
            );
        }
        let data = self.context.input_data_arena.alloc(InputData {
            name: name.clone(),
            bit_width,
            driven_value: RefCell::new(None),
        });
        let value = self.context.signal_arena.alloc(InternalSignal {
            context: self.context,
            module: self,

            data: SignalData::Input { data },
        });
        let input = self.context.input_arena.alloc(Input {
            module: self,

            data,
            value,
        });
        self.inputs.borrow_mut().insert(name, input);
        input
    }

    /// Creates an output for this `Module` called `name` with the same number of bits as `source`, and drives this output with `source`.
    ///
    /// # Panics
    ///
    /// Panics of `source` doesn't belong to this `Module`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let some_signal = m.high();
    /// m.output("my_output", some_signal);
    /// ```
    pub fn output(&'a self, name: impl Into<String>, source: &'a dyn Signal<'a>) -> &Output<'a> {
        let name = name.into();
        let source = source.internal_signal();
        if !ptr::eq(self, source.module) {
            panic!("Cannot output a signal from another module.");
        }
        // TODO: Error if name already exists in this context
        let data = self.context.output_data_arena.alloc(OutputData {
            module: self,

            name: name.clone(),
            source,
            bit_width: source.bit_width(),
        });
        let output = self.context.output_arena.alloc(Output { data });
        self.outputs.borrow_mut().insert(name, output);
        output
    }

    /// Creates a [`Register`] in this `Module` called `name` with `bit_width` bits.
    ///
    /// # Panics
    ///
    /// Panics if `bit_width` is less than [`MIN_SIGNAL_BIT_WIDTH`] or greater than [`MAX_SIGNAL_BIT_WIDTH`], respectively.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let my_reg = m.reg("my_reg", 32);
    /// my_reg.default_value(0xfadebabeu32); // Optional
    /// my_reg.drive_next(!my_reg);
    /// m.output("my_output", my_reg);
    /// ```
    pub fn reg(&'a self, name: impl Into<String>, bit_width: u32) -> &Register<'a> {
        // TODO: Error if name already exists in this context and update docs for Signal::reg_next and Signal::reg_next_with_default to reflect this
        if bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a register with {} bit(s). Signals must not be narrower than {} bit(s).",
                bit_width, MIN_SIGNAL_BIT_WIDTH
            );
        }
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a register with {} bit(s). Signals must not be wider than {} bit(s).",
                bit_width, MAX_SIGNAL_BIT_WIDTH
            );
        }
        let data = self.context.register_data_arena.alloc(RegisterData {
            module: self,

            name: name.into(),
            initial_value: RefCell::new(None),
            bit_width,
            next: RefCell::new(None),
        });
        let value = self.context.signal_arena.alloc(InternalSignal {
            context: self.context,
            module: self,

            data: SignalData::Reg { data },
        });
        self.registers.borrow_mut().push(value);
        self.context.register_arena.alloc(Register { data, value })
    }

    /// Creates a 2:1 [multiplexer](https://en.wikipedia.org/wiki/Multiplexer) that represents `when_true`'s value when `cond` is high, and `when_false`'s value when `cond` is low.
    ///
    /// # Panics
    ///
    /// Panics if `cond`, `when_true`, or `when_false` belong to a different `Module` than `self`, if `cond`'s bit width is not 1, or if the bit widths of `when_true` and `when_false` aren't equal.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let cond = m.input("cond", 1);
    /// let a = m.input("a", 8);
    /// let b = m.input("b", 8);
    /// m.output("my_output", m.mux(cond, a, b)); // Outputs a when cond is high, b otherwise
    /// ```
    pub fn mux(
        &'a self,
        cond: &'a dyn Signal<'a>,
        when_true: &'a dyn Signal<'a>,
        when_false: &'a dyn Signal<'a>,
    ) -> &dyn Signal<'a> {
        let cond = cond.internal_signal();
        let when_true = when_true.internal_signal();
        let when_false = when_false.internal_signal();

        // TODO: This is an optimization to support sugar; if that doesn't go well, remove this
        if when_true == when_false {
            return when_true;
        }

        if !ptr::eq(self, cond.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if !ptr::eq(self, when_true.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if !ptr::eq(self, when_false.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if cond.bit_width() != 1 {
            panic!("Multiplexer conditionals can only be 1 bit wide.");
        }
        if when_true.bit_width() != when_false.bit_width() {
            panic!(
                "Cannot multiplex signals with different bit widths ({} and {}, respectively).",
                when_true.bit_width(),
                when_false.bit_width()
            );
        }
        self.context.signal_arena.alloc(InternalSignal {
            context: self.context,
            module: self,

            data: SignalData::Mux {
                cond,
                when_true,
                when_false,
                bit_width: when_true.bit_width(),
            },
        })
    }

    /// Creates a [`Mem`] in this `Module` called `name` with `address_bit_width` address bits and `element_bit_width` element bits.
    ///
    /// The size of this memory will be `1 << address_bit_width` elements, each `element_bit_width` bits wide.
    ///
    /// # Panics
    ///
    /// Panics if `address_bit_width` or `element_bit_width` is less than [`MIN_SIGNAL_BIT_WIDTH`] or greater than [`MAX_SIGNAL_BIT_WIDTH`], respectively.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let my_mem = m.mem("my_mem", 1, 32);
    /// // Optional, unless no write port is specified
    /// my_mem.initial_contents(&[0xfadebabeu32, 0xdeadbeefu32]);
    /// // Optional, unless no initial contents are specified
    /// my_mem.write_port(m.high(), m.lit(0xabad1deau32, 32), m.high());
    /// m.output("my_output", my_mem.read_port(m.high(), m.high()));
    /// ```
    pub fn mem(
        &'a self,
        name: impl Into<String>,
        address_bit_width: u32,
        element_bit_width: u32,
    ) -> &Mem<'a> {
        // TODO: Error if name already exists in this context
        if address_bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a memory with {} address bit(s). Signals must not be narrower than {} bit(s).",
                address_bit_width, MIN_SIGNAL_BIT_WIDTH
            );
        }
        if address_bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a memory with {} address bit(s). Signals must not be wider than {} bit(s).",
                address_bit_width, MAX_SIGNAL_BIT_WIDTH
            );
        }
        if element_bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a memory with {} element bit(s). Signals must not be narrower than {} bit(s).",
                element_bit_width, MIN_SIGNAL_BIT_WIDTH
            );
        }
        if element_bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!(
                "Cannot create a memory with {} element bit(s). Signals must not be wider than {} bit(s).",
                element_bit_width, MAX_SIGNAL_BIT_WIDTH
            );
        }
        let ret = self.context.mem_arena.alloc(Mem {
            context: self.context,
            module: self,

            name: name.into(),
            address_bit_width,
            element_bit_width,

            initial_contents: RefCell::new(None),

            read_ports: RefCell::new(Vec::new()),
            write_port: RefCell::new(None),
        });
        self.mems.borrow_mut().push(ret);
        ret
    }
}

impl<'a> ModuleParent<'a> for Module<'a> {
    // TODO: Docs, error handling
    fn module(&'a self, instance_name: impl Into<String>, name: impl Into<String>) -> &Module {
        let instance_name = instance_name.into();
        let name = name.into();
        let module = self.context.module_arena.alloc(Module::new(
            self.context,
            Some(self),
            instance_name,
            name,
        ));
        self.modules.borrow_mut().push(module);
        module
    }
}

impl<'a> Eq for &'a Module<'a> {}

impl<'a> Hash for &'a Module<'a> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_usize(*self as *const _ as usize)
    }
}

impl<'a> PartialEq for &'a Module<'a> {
    fn eq(&self, other: &Self) -> bool {
        ptr::eq(*self, *other)
    }
}

// TODO: Move?
// TODO: Doc
// TODO: bit width as const generic param?
#[must_use]
pub struct Input<'a> {
    // TODO: Double-check that we need this (I think we need it for error checking in drive)
    pub(crate) module: &'a Module<'a>,

    pub(crate) data: &'a InputData<'a>,
    pub(crate) value: &'a InternalSignal<'a>,
}

impl<'a> Input<'a> {
    // TODO: Doc
    // TODO: Merge error cases with Instance::drive_input?
    // TODO: Rename i?
    pub fn drive(&'a self, i: &'a dyn Signal<'a>) {
        let i = i.internal_signal();
        // TODO: Change text from instance -> module in appropriate places?
        if let Some(parent) = self.module.parent {
            if !ptr::eq(parent, i.module) {
                // TODO: Clarify?
                panic!("Attempted to drive an instance input with a signal from a different module than that instance's parent module.");
            }
        } else {
            // TODO: Proper panic + test!
            panic!("OH NOES");
        }
        let mut driven_value = self.data.driven_value.borrow_mut();
        if driven_value.is_some() {
            panic!("Attempted to drive an input called \"{}\" on an instance of \"{}\", but this input is already driven for this instance.", self.data.name, self.module.name);
        }
        if self.data.bit_width != i.bit_width() {
            panic!("Attempted to drive an input called \"{}\" on an instance of \"{}\", but this input and the provided signal have different bit widths ({} and {}, respectively).", self.data.name, self.module.name, self.data.bit_width, i.bit_width());
        }
        *driven_value = Some(i);
    }
}

impl<'a> GetInternalSignal<'a> for Input<'a> {
    fn internal_signal(&'a self) -> &'a InternalSignal<'a> {
        self.value
    }
}

impl<'a> GetInternalSignal<'a> for Output<'a> {
    fn internal_signal(&'a self) -> &'a InternalSignal<'a> {
        let parent = self.data.module.parent.expect("TODO better error pls");
        self.data.module.context.signal_arena.alloc(InternalSignal {
            context: self.data.module.context,
            module: parent,

            data: SignalData::Output { data: self.data },
        })
    }
}

pub(crate) struct InputData<'a> {
    // TODO: Do we need this stored here too?
    pub name: String,
    pub bit_width: u32,
    // TODO: Rename?
    pub driven_value: RefCell<Option<&'a InternalSignal<'a>>>,
}

// TODO: Move?
// TODO: Doc
// TODO: must_use?
// TODO: bit width as const generic param?
pub struct Output<'a> {
    pub(crate) data: &'a OutputData<'a>,
}

pub(crate) struct OutputData<'a> {
    // TODO: Do we need this?
    pub module: &'a Module<'a>,

    // TODO: Do we need this stored here too?
    pub name: String,
    pub source: &'a InternalSignal<'a>,
    pub bit_width: u32,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[should_panic(
        expected = "Cannot create a literal with 0 bit(s). Signals must not be narrower than 1 bit(s)."
    )]
    fn lit_bit_width_lt_min_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.lit(false, 0);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create a literal with 129 bit(s). Signals must not be wider than 128 bit(s)."
    )]
    fn lit_bit_width_gt_max_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.lit(false, 129);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into the specified bit width '7'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_1() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.lit(128u32, 7);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into the specified bit width '2'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_2() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.lit(128u64, 2);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '1023' into the specified bit width '4'. The value '1023' requires a bit width of at least 10 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_3() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.lit(1023u128, 4);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '65536' into the specified bit width '1'. The value '65536' requires a bit width of at least 17 bit(s)."
    )]
    fn lit_value_cannot_bit_into_bit_width_error_4() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.lit(65536u32, 1);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create an input with 0 bit(s). Signals must not be narrower than 1 bit(s)."
    )]
    fn input_width_lt_min_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.input("i", 0);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create an input with 129 bit(s). Signals must not be wider than 128 bit(s)."
    )]
    fn input_width_gt_max_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.input("i", 129);
    }

    #[test]
    #[should_panic(expected = "Cannot output a signal from another module.")]
    fn output_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");

        let m2 = c.module("b", "B");
        let i = m2.high();

        // Panic
        m1.output("a", i);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create a register with 0 bit(s). Signals must not be narrower than 1 bit(s)."
    )]
    fn reg_bit_width_lt_min_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.reg("r", 0);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create a register with 129 bit(s). Signals must not be wider than 128 bit(s)."
    )]
    fn reg_bit_width_gt_max_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.reg("r", 129);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn mux_cond_separate_module_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(false, 1);

        let b = c.module("b", "B");
        let l2 = b.lit(32u8, 8);
        let l3 = b.lit(32u8, 8);

        // Panic
        let _ = b.mux(l1, l2, l3);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn mux_when_true_separate_module_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(32u8, 8);

        let b = c.module("b", "B");
        let l2 = b.lit(true, 1);
        let l3 = b.lit(32u8, 8);

        // Panic
        let _ = b.mux(l2, l1, l3);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn mux_when_false_separate_module_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(32u8, 8);

        let b = c.module("b", "B");
        let l2 = b.lit(true, 1);
        let l3 = b.lit(32u8, 8);

        // Panic
        let _ = b.mux(l2, l3, l1);
    }

    #[test]
    #[should_panic(expected = "Multiplexer conditionals can only be 1 bit wide.")]
    fn mux_cond_bit_width_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(2u8, 2);
        let l2 = a.lit(32u8, 8);
        let l3 = a.lit(32u8, 8);

        // Panic
        let _ = a.mux(l1, l2, l3);
    }

    #[test]
    #[should_panic(
        expected = "Cannot multiplex signals with different bit widths (3 and 5, respectively)."
    )]
    fn mux_true_false_bit_width_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(false, 1);
        let l2 = a.lit(3u8, 3);
        let l3 = a.lit(3u8, 5);

        // Panic
        let _ = a.mux(l1, l2, l3);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create a memory with 0 address bit(s). Signals must not be narrower than 1 bit(s)."
    )]
    fn mem_address_bit_width_lt_min_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.mem("mem", 0, 1);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create a memory with 129 address bit(s). Signals must not be wider than 128 bit(s)."
    )]
    fn mem_address_bit_width_gt_max_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.mem("mem", 129, 1);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create a memory with 0 element bit(s). Signals must not be narrower than 1 bit(s)."
    )]
    fn mem_element_bit_width_lt_min_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.mem("mem", 1, 0);
    }

    #[test]
    #[should_panic(
        expected = "Cannot create a memory with 129 element bit(s). Signals must not be wider than 128 bit(s)."
    )]
    fn mem_element_bit_width_gt_max_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        // Panic
        let _ = m.mem("mem", 1, 129);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive an instance input with a signal from a different module than that instance's parent module."
    )]
    fn input_drive_different_module_than_parent_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");

        let inner = m2.module("inner", "Inner");
        let a = inner.input("a", 1);

        // Panic
        a.drive(i1);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive an input called \"a\" on an instance of \"Inner\", but this input is already driven for this instance."
    )]
    fn input_drive_already_driven_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        let inner = m.module("inner", "Inner");
        let a = inner.input("a", 1);

        a.drive(m.input("i1", 1));

        // Panic
        a.drive(m.input("i2", 1));
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive an input called \"a\" on an instance of \"Inner\", but this input and the provided signal have different bit widths (1 and 32, respectively)."
    )]
    fn input_drive_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");

        let inner = m.module("inner", "Inner");
        let a = inner.input("a", 1);

        // Panic
        a.drive(m.input("i1", 32));
    }
}


================================================
FILE: kaze/src/graph/register.rs
================================================
use super::constant::*;
use super::internal_signal::*;
use super::module::*;
use super::signal::*;

use std::cell::RefCell;
use std::ptr;

/// A hardware register, created by the [`Module::reg`] method.
///
/// A `Register` is a stateful component that behaves like a [D flip-flop](https://en.wikipedia.org/wiki/Flip-flop_(electronics)#D_flip-flop) (more precisely as a [positive-edge-triggered D flip-flop](https://en.wikipedia.org/wiki/Flip-flop_(electronics)#Classical_positive-edge-triggered_D_flip-flop)).
///
/// It always has a current value represented by the [`value`] field (often referred to as `Q`) and a next value specified by the [`drive_next`] method (often referred to as `D`).
/// It will hold its [`value`] until a positive edge of its [`Module`]'s implicit clock occurs, at which point [`value`] will be updated to reflect the next value.
///
/// Optionally, it also has a default value specified by the [`default_value`] method. If at any time its [`Module`]'s implicit reset is driven low, the register's [`value`] will reflect the default value.
/// Default values are used to provide a known register state on system power-on and reset, but are often omitted to reduce combinational logic (which ultimately is how default values are typically implemented), especially for registers on timing-critical data paths.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("m", "MyModule");
///
/// let my_reg = m.reg("my_reg", 32);
/// my_reg.default_value(0xfadebabeu32); // Optional
/// my_reg.drive_next(!my_reg);
/// m.output("my_output", my_reg);
/// ```
///
/// [`default_value`]: Self::default_value
/// [`drive_next`]: Self::drive_next
/// [`value`]: Self::value
#[must_use]
pub struct Register<'a> {
    pub(crate) data: &'a RegisterData<'a>,
    /// This `Register`'s current value.
    pub(crate) value: &'a InternalSignal<'a>,
}

impl<'a> Register<'a> {
    /// Specifies the default value for this `Register`.
    ///
    /// This `Register`'s [`value`] will reflect this default value when this `Register`'s [`Module`]'s implicit reset is asserted.
    ///
    /// By default, a `Register` does not have a default value, and it is not required to specify one. If a default value is not specified, then this `Register`'s [`value`] will not change when its [`Module`]'s implicit reset is asserted.
    ///
    /// # Panics
    ///
    /// Panics if this `Register` already has a default value specified, or if the specified `value` doesn't fit into this `Register`'s bit width.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let my_reg = m.reg("my_reg", 32);
    /// my_reg.default_value(0xfadebabeu32); // Optional
    /// my_reg.drive_next(!my_reg);
    /// m.output("my_output", my_reg);
    /// ```
    ///
    /// [`value`]: Self::value
    pub fn default_value(&'a self, value: impl Into<Constant>) {
        if self.data.initial_value.borrow().is_some() {
            panic!("Attempted to specify a default value for register \"{}\" in module \"{}\", but this register already has a default value.", self.data.name, self.data.module.name);
        }
        let value = value.into();
        let required_bits = value.required_bits();
        if required_bits > self.data.bit_width {
            let numeric_value = value.numeric_value();
            panic!("Cannot fit the specified value '{}' into register \"{}\"'s bit width '{}'. The value '{}' requires a bit width of at least {} bit(s).", numeric_value, self.data.name, self.data.bit_width, numeric_value, required_bits);
        }
        *self.data.initial_value.borrow_mut() = Some(value);
    }

    /// Specifies the next value for this `Register`.
    ///
    /// A `Register` will hold its [`value`] until a positive edge of its [`Module`]'s implicit clock occurs, at which point [`value`] will be updated to reflect this next value.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `n` belong to different [`Module`]s, if the bit widths of `self` and `n` aren't equal, or if this `Register`'s next value is already driven.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let my_reg = m.reg("my_reg", 32);
    /// my_reg.default_value(0xfadebabeu32); // Optional
    /// my_reg.drive_next(!my_reg); // my_reg's value will toggle with each positive clock edge
    /// m.output("my_output", my_reg);
    /// ```
    ///
    /// [`value`]: Self::value
    pub fn drive_next(&'a self, n: &'a dyn Signal<'a>) {
        let n = n.internal_signal();
        if !ptr::eq(self.data.module, n.module) {
            panic!("Attempted to drive register \"{}\"'s next value with a signal from another module.", self.data.name);
        }
        if n.bit_width() != self.data.bit_width {
            panic!("Attempted to drive register \"{}\"'s next value with a signal that has a different bit width than the register ({} and {}, respectively).", self.data.name, n.bit_width(), self.data.bit_width);
        }
        if self.data.next.borrow().is_some() {
            panic!("Attempted to drive register \"{}\"'s next value in module \"{}\", but this register's next value is already driven.", self.data.name, self.data.module.name);
        }
        *self.data.next.borrow_mut() = Some(n);
    }
}

pub(crate) struct RegisterData<'a> {
    pub module: &'a Module<'a>,

    pub name: String,
    pub initial_value: RefCell<Option<Constant>>,
    pub bit_width: u32,
    pub next: RefCell<Option<&'a InternalSignal<'a>>>,
}

impl<'a> GetInternalSignal<'a> for Register<'a> {
    fn internal_signal(&'a self) -> &'a InternalSignal<'a> {
        self.value
    }
}

#[cfg(test)]
mod tests {
    use crate::*;

    #[test]
    #[should_panic(
        expected = "Attempted to specify a default value for register \"r\" in module \"A\", but this register already has a default value."
    )]
    fn default_value_already_specified_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let r = m.reg("r", 32);

        r.default_value(0xfadebabeu32);

        // Panic
        r.default_value(0xdeadbeefu32);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into register \"r\"'s bit width '7'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_1() {
        let c = Context::new();

        let m = c.module("a", "A");
        let r = m.reg("r", 7);

        // Panic
        r.default_value(128u32);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '128' into register \"r\"'s bit width '2'. The value '128' requires a bit width of at least 8 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_2() {
        let c = Context::new();

        let m = c.module("a", "A");
        let r = m.reg("r", 2);

        // Panic
        r.default_value(128u64);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '1023' into register \"r\"'s bit width '4'. The value '1023' requires a bit width of at least 10 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_3() {
        let c = Context::new();

        let m = c.module("a", "A");
        let r = m.reg("r", 4);

        // Panic
        r.default_value(1023u128);
    }

    #[test]
    #[should_panic(
        expected = "Cannot fit the specified value '65536' into register \"r\"'s bit width '1'. The value '65536' requires a bit width of at least 17 bit(s)."
    )]
    fn default_value_cannot_bit_into_bit_width_error_4() {
        let c = Context::new();

        let m = c.module("a", "A");
        let r = m.reg("r", 1);

        // Panic
        r.default_value(65536u32);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive register \"r\"'s next value with a signal from another module."
    )]
    fn drive_next_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let l = m1.lit(true, 1);

        let m2 = c.module("b", "B");
        let r = m2.reg("r", 1);

        // Panic
        r.drive_next(l);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive register \"r\"'s next value with a signal that has a different bit width than the register (5 and 3, respectively)."
    )]
    fn drive_next_incompatible_bit_width_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let r = m.reg("r", 3);
        let i = m.input("i", 5);

        // Panic
        r.drive_next(i);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to drive register \"r\"'s next value in module \"A\", but this register's next value is already driven."
    )]
    fn drive_next_already_driven_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let r = m.reg("r", 32);
        let i = m.input("i", 32);

        r.drive_next(i);

        // Panic
        r.drive_next(i);
    }
}


================================================
FILE: kaze/src/graph/signal.rs
================================================
use super::constant::*;
use super::internal_signal::*;

use std::ops::{Add, BitAnd, BitOr, BitXor, Mul, Not, Shl, Shr, Sub};
use std::ptr;

/// The minimum allowed bit width for any given [`Signal`].
///
/// This is currently set to `1`, and is not likely to change in future versions of this library.
pub const MIN_SIGNAL_BIT_WIDTH: u32 = 1;
/// The maximum allowed bit width for any given [`Signal`].
///
/// This is currently set to `128` to simplify simulator code generation, since it allows the generated code to rely purely on native integer types provided by Rust's standard library for storage, arithmetic, etc. Larger widths may be supported in a future version of this library.
pub const MAX_SIGNAL_BIT_WIDTH: u32 = 128;

/// A collection of 1 or more bits driven by some source.
///
/// A `Signal` can be created by several [`Module`] methods (eg. [`lit`]) or as a result of combining existing `Signal`s (eg. [`concat`]). `Signal`s are local to their respective [`Module`]s.
///
/// A `Signal` behaves similarly to a `wire` in Verilog, except that it's always driven.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("m", "MyModule");
/// let a = m.lit(0xffu8, 8); // 8-bit signal
/// let b = m.input("my_input", 27); // 27-bit signal
/// let c = b.bits(7, 0); // 8-bit signal
/// let d = a + c; // 8-bit signal
/// m.output("my_output", d); // 8-bit output driven by d
/// ```
///
/// [`concat`]: Self::concat
/// [`lit`]: Module::lit
pub trait Signal<'a>: GetInternalSignal<'a> {
    /// Returns the bit width of the given `Signal`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// assert_eq!(m.lit(42u32, 7).bit_width(), 7);
    /// assert_eq!(m.input("i", 27).bit_width(), 27);
    /// assert_eq!(m.reg("some_reg", 46).bit_width(), 46);
    /// assert_eq!((!m.low()).bit_width(), 1);
    /// assert_eq!((m.lit(25u8, 8) + m.lit(42u8, 8)).bit_width(), 8);
    /// assert_eq!((m.lit(1u8, 1) * m.lit(2u8, 2)).bit_width(), 3);
    /// assert_eq!(m.lit(1u8, 1).mul_signed(m.lit(2u8, 2)).bit_width(), 3);
    /// assert_eq!(m.lit(false, 1).reg_next("some_other_reg").bit_width(), 1);
    /// assert_eq!(m.lit(true, 1).reg_next_with_default("yet_another_reg", false).bit_width(), 1);
    /// assert_eq!((m.high() & m.low()).bit_width(), 1);
    /// assert_eq!((m.high() | m.low()).bit_width(), 1);
    /// assert_eq!(m.lit(12u32, 100).bit(30).bit_width(), 1);
    /// assert_eq!(m.lit(1u32, 99).bits(37, 29).bit_width(), 9);
    /// assert_eq!(m.high().repeat(35).bit_width(), 35);
    /// assert_eq!(m.lit(1u32, 20).concat(m.high()).bit_width(), 21);
    /// assert_eq!((m.lit(0x80u32, 8) << m.lit(true, 1)).bit_width(), 8);
    /// assert_eq!((m.lit(0x80u32, 8) >> m.lit(true, 1)).bit_width(), 8);
    /// assert_eq!(m.lit(0x80u32, 8).shr_arithmetic(m.lit(true, 1)).bit_width(), 8);
    /// assert_eq!(m.lit(0xaau32, 8).eq(m.lit(0xaau32, 8)).bit_width(), 1);
    /// assert_eq!(m.lit(0xaau32, 8).ne(m.lit(0xaau32, 8)).bit_width(), 1);
    /// assert_eq!(m.lit(0xaau32, 8).lt(m.lit(0xaau32, 8)).bit_width(), 1);
    /// assert_eq!(m.lit(0xaau32, 8).le(m.lit(0xaau32, 8)).bit_width(), 1);
    /// assert_eq!(m.lit(0xaau32, 8).gt(m.lit(0xaau32, 8)).bit_width(), 1);
    /// assert_eq!(m.lit(0xaau32, 8).ge(m.lit(0xaau32, 8)).bit_width(), 1);
    /// assert_eq!(m.mux(m.low(), m.lit(5u32, 4), m.lit(6u32, 4)).bit_width(), 4);
    /// ```
    #[must_use]
    fn bit_width(&'a self) -> u32 {
        let s = self.internal_signal();
        s.bit_width()
    }

    /// Creates a `Signal` that represents the value of the single bit of this `Signal` at index `index`, where `index` equal to `0` represents this `Signal`'s least significant bit.
    ///
    /// # Panics
    ///
    /// Panics if `index` is greater than or equal to this `Signal`'s `bit_width`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit = m.lit(0b0110u32, 4);
    /// let bit_0 = lit.bit(0); // Represents 0
    /// let bit_1 = lit.bit(1); // Represents 1
    /// let bit_2 = lit.bit(2); // Represents 1
    /// let bit_3 = lit.bit(3); // Represents 0
    /// ```
    fn bit(&'a self, index: u32) -> &'a dyn Signal<'a> {
        let s = self.internal_signal();
        if index >= s.bit_width() {
            panic!("Attempted to take bit index {} from a signal with a width of {} bits. Bit indices must be in the range [0, {}] for a signal with a width of {} bits.", index, s.bit_width(), s.bit_width() - 1, s.bit_width());
        }
        s.context.signal_arena.alloc(InternalSignal {
            context: s.context,
            module: s.module,

            data: SignalData::Bits {
                source: s,
                range_high: index,
                range_low: index,
            },
        })
    }

    /// Creates a `Signal` that represents a contiguous subset of the bits of this `Signal`, starting at `range_low` as the least significant bit and ending at `range_high` as the most significant bit, inclusive.
    ///
    /// # Panics
    ///
    /// Panics if either `range_low` or `range_high` is greater than or equal to the bit width of this `Signal`, or if `range_low` is greater than `range_high`.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit = m.lit(0b0110u32, 4);
    /// let bits_210 = lit.bits(2, 0); // Represents 0b110
    /// let bits_321 = lit.bits(3, 1); // Represents 0b011
    /// let bits_10 = lit.bits(1, 0); // Represents 0b10
    /// let bits_32 = lit.bits(3, 2); // Represents 0b01
    /// let bits_2 = lit.bits(2, 2); // Represents 1, equivalent to lit.bit(2)
    /// ```
    fn bits(&'a self, range_high: u32, range_low: u32) -> &'a dyn Signal<'a> {
        let s = self.internal_signal();
        if range_low >= s.bit_width() {
            panic!("Cannot specify a range of bits where the lower bound is greater than or equal to the number of bits in the source signal. The bounds must be in the range [0, {}] for a signal with a width of {} bits, but a lower bound of {} was given.", s.bit_width() - 1, s.bit_width(), range_low);
        }
        if range_high >= s.bit_width() {
            panic!("Cannot specify a range of bits where the upper bound is greater than or equal to the number of bits in the source signal. The bounds must be in the range [0, {}] for a signal with a width of {} bits, but an upper bound of {} was given.", s.bit_width() - 1, s.bit_width(), range_high);
        }
        if range_low > range_high {
            panic!("Cannot specify a range of bits where the lower bound is greater than the upper bound.");
        }
        s.context.signal_arena.alloc(InternalSignal {
            context: s.context,
            module: s.module,

            data: SignalData::Bits {
                source: s,
                range_high,
                range_low,
            },
        })
    }

    /// Creates a `Signal` that represents this `Signal` repeated `count` times.
    ///
    /// # Panics
    ///
    /// Panics if `self.bit_width() * count` is less than [`MIN_SIGNAL_BIT_WIDTH`] or greater than [`MAX_SIGNAL_BIT_WIDTH`].
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit = m.lit(0xau32, 4);
    /// let repeat_1 = lit.repeat(1); // Equivalent to just lit
    /// let repeat_2 = lit.repeat(2); // Equivalent to 8-bit lit with value 0xaa
    /// let repeat_5 = lit.repeat(5); // Equivalent to 20-bit lit with value 0xaaaaa
    /// let repeat_8 = lit.repeat(8); // Equivalent to 32-bit lit with value 0xaaaaaaaa
    /// ```
    fn repeat(&'a self, count: u32) -> &'a dyn Signal<'a> {
        let s = self.internal_signal();
        let bit_width = s.bit_width() * count;
        if bit_width < MIN_SIGNAL_BIT_WIDTH {
            panic!("Attempted to repeat a {}-bit signal {} times, but this would result in a bit width of {}, which is less than the minimal signal bit width of {} bit(s).", s.bit_width(), count, bit_width, MIN_SIGNAL_BIT_WIDTH);
        }
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!("Attempted to repeat a {}-bit signal {} times, but this would result in a bit width of {}, which is greater than the maximum signal bit width of {} bit(s).", s.bit_width(), count, bit_width, MAX_SIGNAL_BIT_WIDTH);
        }
        s.context.signal_arena.alloc(InternalSignal {
            context: s.context,
            module: s.module,

            data: SignalData::Repeat {
                source: s,
                count,
                bit_width,
            },
        })
    }

    /// Creates a `Signal` that represents this `Signal` concatenated with `rhs`.
    ///
    /// `self` represents the upper bits in the resulting `Signal`, and `rhs` represents the lower bits.
    ///
    /// # Panics
    ///
    /// Panics if `self.bit_width() + rhs.bit_width()` is greater than [`MAX_SIGNAL_BIT_WIDTH`].
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xffu32, 8);
    /// let concat_1 = lit_a.concat(lit_b); // Equivalent to 12-bit lit with value 0xaff
    /// let concat_2 = lit_b.concat(lit_a); // Equivalent to 12-bit lit with value 0xffa
    /// let concat_3 = lit_a.concat(lit_a); // Equivalent to 8-bit lit with value 0xaa
    /// ```
    fn concat(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        let bit_width = lhs.bit_width() + rhs.bit_width();
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!("Attempted to concatenate signals with {} bit(s) and {} bit(s) respectively, but this would result in a bit width of {}, which is greater than the maximum signal bit width of {} bit(s).", lhs.bit_width(), rhs.bit_width(), bit_width, MAX_SIGNAL_BIT_WIDTH);
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::Concat {
                lhs,
                rhs,
                bit_width,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of a bitwise boolean equality comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, or if the bit widths of `self` and `rhs` aren't equal.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let eq_1 = lit_a.eq(lit_a); // Equivalent to m.high()
    /// let eq_2 = lit_b.eq(lit_b); // Equivalent to m.high()
    /// let eq_3 = lit_a.eq(lit_b); // Equivalent to m.low()
    /// let eq_4 = lit_b.eq(lit_a); // Equivalent to m.low()
    /// ```
    fn eq(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::Equal,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of a bitwise boolean inequality comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, or if the bit widths of `self` and `rhs` aren't equal.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let ne_1 = lit_a.ne(lit_a); // Equivalent to m.low()
    /// let ne_2 = lit_b.ne(lit_b); // Equivalent to m.low()
    /// let ne_3 = lit_a.ne(lit_b); // Equivalent to m.high()
    /// let ne_4 = lit_b.ne(lit_a); // Equivalent to m.high()
    /// ```
    fn ne(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::NotEqual,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of an unsigned `<` comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, or if the bit widths of `self` and `rhs` aren't equal.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let lt_1 = lit_a.lt(lit_a); // Equivalent to m.low()
    /// let lt_2 = lit_b.lt(lit_b); // Equivalent to m.low()
    /// let lt_3 = lit_a.lt(lit_b); // Equivalent to m.high()
    /// let lt_4 = lit_b.lt(lit_a); // Equivalent to m.low()
    /// ```
    fn lt(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::LessThan,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of an unsigned `<=` comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, or if the bit widths of `self` and `rhs` aren't equal.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let le_1 = lit_a.le(lit_a); // Equivalent to m.high()
    /// let le_2 = lit_b.le(lit_b); // Equivalent to m.high()
    /// let le_3 = lit_a.le(lit_b); // Equivalent to m.high()
    /// let le_4 = lit_b.le(lit_a); // Equivalent to m.low()
    /// ```
    fn le(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::LessThanEqual,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of an unsigned `>` comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, or if the bit widths of `self` and `rhs` aren't equal.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let gt_1 = lit_a.gt(lit_a); // Equivalent to m.low()
    /// let gt_2 = lit_b.gt(lit_b); // Equivalent to m.low()
    /// let gt_3 = lit_a.gt(lit_b); // Equivalent to m.low()
    /// let gt_4 = lit_b.gt(lit_a); // Equivalent to m.high()
    /// ```
    fn gt(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::GreaterThan,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of an unsigned `>=` comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, or if the bit widths of `self` and `rhs` aren't equal.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let ge_1 = lit_a.ge(lit_a); // Equivalent to m.high()
    /// let ge_2 = lit_b.ge(lit_b); // Equivalent to m.high()
    /// let ge_3 = lit_a.ge(lit_b); // Equivalent to m.low()
    /// let ge_4 = lit_b.ge(lit_a); // Equivalent to m.high()
    /// ```
    fn ge(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::GreaterThanEqual,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of a signed `<` comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, if the bit widths of `self` and `rhs` aren't equal, or if the bit widths of `self` and `rhs` are 1.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let lt_signed_1 = lit_a.lt_signed(lit_a); // Equivalent to m.low()
    /// let lt_signed_2 = lit_b.lt_signed(lit_b); // Equivalent to m.low()
    /// let lt_signed_3 = lit_a.lt_signed(lit_b); // Equivalent to m.high()
    /// let lt_signed_4 = lit_b.lt_signed(lit_a); // Equivalent to m.low()
    /// ```
    fn lt_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        if lhs.bit_width() == 1 {
            panic!("Cannot perform signed comparison of 1-bit signals.");
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::LessThanSigned,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of a signed `<=` comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, if the bit widths of `self` and `rhs` aren't equal, or if the bit widths of `self` and `rhs` are 1.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let le_signed_1 = lit_a.le_signed(lit_a); // Equivalent to m.high()
    /// let le_signed_2 = lit_b.le_signed(lit_b); // Equivalent to m.high()
    /// let le_signed_3 = lit_a.le_signed(lit_b); // Equivalent to m.high()
    /// let le_signed_4 = lit_b.le_signed(lit_a); // Equivalent to m.low()
    /// ```
    fn le_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        if lhs.bit_width() == 1 {
            panic!("Cannot perform signed comparison of 1-bit signals.");
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::LessThanEqualSigned,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of a signed `>` comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, if the bit widths of `self` and `rhs` aren't equal, or if the bit widths of `self` and `rhs` are 1.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let gt_signed_1 = lit_a.gt_signed(lit_a); // Equivalent to m.low()
    /// let gt_signed_2 = lit_b.gt_signed(lit_b); // Equivalent to m.low()
    /// let gt_signed_3 = lit_a.gt_signed(lit_b); // Equivalent to m.low()
    /// let gt_signed_4 = lit_b.gt_signed(lit_a); // Equivalent to m.high()
    /// ```
    fn gt_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        if lhs.bit_width() == 1 {
            panic!("Cannot perform signed comparison of 1-bit signals.");
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::GreaterThanSigned,
            },
        })
    }

    /// Creates a `Signal` that represents the single-bit result of a signed `>=` comparison between `self` and `rhs`.
    ///
    /// # Panics
    ///
    /// Panics if `self` and `rhs` belong to different [`Module`]s, if the bit widths of `self` and `rhs` aren't equal, or if the bit widths of `self` and `rhs` are 1.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lit_a = m.lit(0xau32, 4);
    /// let lit_b = m.lit(0xbu32, 4);
    /// let ge_signed_1 = lit_a.ge_signed(lit_a); // Equivalent to m.high()
    /// let ge_signed_2 = lit_b.ge_signed(lit_b); // Equivalent to m.high()
    /// let ge_signed_3 = lit_a.ge_signed(lit_b); // Equivalent to m.low()
    /// let ge_signed_4 = lit_b.ge_signed(lit_a); // Equivalent to m.high()
    /// ```
    fn ge_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        if lhs.bit_width() != rhs.bit_width() {
            panic!(
                "Signals have different bit widths ({} and {}, respectively).",
                lhs.bit_width(),
                rhs.bit_width()
            );
        }
        if lhs.bit_width() == 1 {
            panic!("Cannot perform signed comparison of 1-bit signals.");
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ComparisonBinOp {
                lhs,
                rhs,
                op: ComparisonBinOp::GreaterThanEqualSigned,
            },
        })
    }

    /// Combines two `Signal`s, producing a new `Signal` that represents `self` arithmetically shifted right by `rhs` bits.
    ///
    /// The result is truncated to `self`'s `bit_width`. If `rhs` specifies a value that's greater than or equal to `self`'s `bit_width`, the resulting value will be all `self`'s top bit repeated `self`'s `bit_width` times.
    ///
    /// # Panics
    ///
    /// Panics if `lhs` and `rhs` belong to different [`Module`]s.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lhs = m.lit(0x80000000u32, 32);
    /// let rhs = m.lit(1u32, 1);
    /// let shifted = lhs.shr_arithmetic(rhs); // Equivalent to m.lit(0xc0000000u32, 32)
    /// ```
    fn shr_arithmetic(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::ShiftBinOp {
                lhs,
                rhs,
                op: ShiftBinOp::ShrArithmetic,
                bit_width: lhs.bit_width(),
            },
        })
    }

    /// Combines two `Signal`s, producing a new `Signal` that represents the signed product of the original two `Signal`s.
    ///
    /// The product's `bit_width` is equal to `self.bit_width() + rhs.bit_width()`.
    ///
    /// # Panics
    ///
    /// Panics if `lhs` and `rhs` belong to different [`Module`]s, or if `self.bit_width() + rhs.bit_width()` is greater than [`MAX_SIGNAL_BIT_WIDTH`].
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let lhs = m.lit(4u32, 3); // -4
    /// let rhs = m.lit(5u32, 4);
    /// let sum = lhs.mul_signed(rhs); // Equivalent to m.lit(108u32, 7), -20
    /// ```
    fn mul_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
        let lhs = self.internal_signal();
        let rhs = rhs.internal_signal();
        if !ptr::eq(lhs.module, rhs.module) {
            panic!("Attempted to combine signals from different modules.");
        }
        let bit_width = lhs.bit_width() + rhs.bit_width();
        if bit_width > MAX_SIGNAL_BIT_WIDTH {
            panic!("Attempted to multiply a {}-bit with a {}-bit signal, but this would result in a bit width of {}, which is greater than the maximum signal bit width of {} bit(s).", lhs.bit_width(), rhs.bit_width(), bit_width, MAX_SIGNAL_BIT_WIDTH);
        }
        lhs.context.signal_arena.alloc(InternalSignal {
            context: lhs.context,
            module: lhs.module,

            data: SignalData::MulSigned {
                lhs,
                rhs,
                bit_width,
            },
        })
    }

    /// Creates a 2:1 [multiplexer](https://en.wikipedia.org/wiki/Multiplexer) that represents `when_true`'s value when `self` is high, and `when_false`'s value when `self` is low.
    ///
    /// This is a convenience wrapper for [`Module::mux`].
    ///
    /// # Panics
    ///
    /// Panics if `when_true` or `when_false` belong to a different [`Module`] than `self`, if `self`'s bit width is not 1, or if the bit widths of `when_true` and `when_false` aren't equal.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let cond = m.input("cond", 1);
    /// let a = m.input("a", 8);
    /// let b = m.input("b", 8);
    /// m.output("my_output", cond.mux(a, b)); // Outputs a when cond is high, b otherwise
    /// ```
    // TODO: This is currently only used to support sugar; if it doesn't work out, remove this
    fn mux(
        &'a self,
        when_true: &'a dyn Signal<'a>,
        when_false: &'a dyn Signal<'a>,
    ) -> &'a dyn Signal<'a> {
        let s = self.internal_signal();
        s.module.mux(s, when_true, when_false)
    }
}

macro_rules! impl_extensions {
    ($($t:ty),*) => ($(
        impl<'a, S: Into<&'a dyn Signal<'a>>> Add<S> for &'a $t {
            type Output = &'a dyn Signal<'a>;

            /// Combines two `Signal`s, producing a new `Signal` that represents the sum of the original two `Signal`s.
            ///
            /// The sum is truncated to the `Signal`'s `bit_width`. If a carry bit is desired, the operands can be [`concat`]enated with a `0` bit before the operation.
            ///
            /// # Panics
            ///
            /// Panics if `lhs` and `rhs` belong to different [`Module`]s, or if the bit widths of `lhs` and `rhs` aren't equal.
            ///
            /// # Examples
            ///
            /// ```
            /// use kaze::*;
            ///
            /// let c = Context::new();
            ///
            /// let m = c.module("m", "MyModule");
            ///
            /// let lhs = m.lit(1u32, 32);
            /// let rhs = m.lit(2u32, 32);
            /// let sum = lhs + rhs; // Equivalent to m.lit(3u32, 32)
            ///
            /// let lhs = m.low().concat(m.lit(0xffffffffu32, 32)); // Concat 0 bits with operands for carry
            /// let rhs = m.low().concat(m.lit(0x00000001u32, 32));
            /// let carry_sum = lhs + rhs; // Equivalent to m.lit(0x100000000u64, 33)
            /// let sum = carry_sum.bits(31, 0); // Equivalent to m.lit(0u32, 32)
            /// let carry = carry_sum.bit(32); // Equivalent to m.lit(true, 1)
            /// ```
            ///
            /// [`concat`]: Signal::concat
            fn add(self, rhs: S) -> Self::Output {
                let lhs = self.internal_signal();
                let rhs = rhs.into().internal_signal();
                if !ptr::eq(lhs.module, rhs.module) {
                    panic!("Attempted to combine signals from different modules.");
                }
                if lhs.bit_width() != rhs.bit_width() {
                    panic!(
                        "Signals have different bit widths ({} and {}, respectively).",
                        lhs.bit_width(),
                        rhs.bit_width()
                    );
                }
                lhs.context.signal_arena.alloc(InternalSignal {
                    context: lhs.context,
                    module: lhs.module,

                    data: SignalData::AdditiveBinOp {
                        lhs,
                        rhs,
                        op: AdditiveBinOp::Add,
                        bit_width: lhs.bit_width(),
                    },
                })
            }
        }

        impl<'a, S: Into<&'a dyn Signal<'a>>> BitAnd<S> for &'a $t {
            type Output = &'a dyn Signal<'a>;

            /// Combines two `Signal`s, producing a new `Signal` whose bits represent the bitwise `&` of each of the bits of the original two `Signal`s.
            ///
            /// # Panics
            ///
            /// Panics if `lhs` and `rhs` belong to different [`Module`]s, or if the bit widths of `lhs` and `rhs` aren't equal.
            ///
            /// # Examples
            ///
            /// ```
            /// use kaze::*;
            ///
            /// let c = Context::new();
            ///
            /// let m = c.module("m", "MyModule");
            ///
            /// let lhs = m.low();
            /// let rhs = m.high();
            /// let single_bitand = lhs & rhs;
            ///
            /// let lhs = m.input("in1", 3);
            /// let rhs = m.input("in2", 3);
            /// let multi_bitand = lhs & rhs;
            /// ```
            fn bitand(self, rhs: S) -> Self::Output {
                let lhs = self.internal_signal();
                let rhs = rhs.into().internal_signal();
                if !ptr::eq(lhs.module, rhs.module) {
                    panic!("Attempted to combine signals from different modules.");
                }
                if lhs.bit_width() != rhs.bit_width() {
                    panic!(
                        "Signals have different bit widths ({} and {}, respectively).",
                        lhs.bit_width(),
                        rhs.bit_width()
                    );
                }
                lhs.context.signal_arena.alloc(InternalSignal {
                    context: lhs.context,
                    module: lhs.module,

                    data: SignalData::SimpleBinOp {
                        lhs,
                        rhs,
                        op: SimpleBinOp::BitAnd,
                        bit_width: lhs.bit_width(),
                    },
                })
            }
        }

        impl<'a, S: Into<&'a dyn Signal<'a>>> BitOr<S> for &'a $t {
            type Output = &'a dyn Signal<'a>;

            /// Combines two `Signal`s, producing a new `Signal` whose bits represent the bitwise `|` of each of the bits of the original two `Signal`s.
            ///
            /// # Panics
            ///
            /// Panics if `lhs` and `rhs` belong to different [`Module`]s, or if the bit widths of `lhs` and `rhs` aren't equal.
            ///
            /// # Examples
            ///
            /// ```
            /// use kaze::*;
            ///
            /// let c = Context::new();
            ///
            /// let m = c.module("m", "MyModule");
            ///
            /// let lhs = m.low();
            /// let rhs = m.high();
            /// let single_bitor = lhs | rhs;
            ///
            /// let lhs = m.input("in1", 3);
            /// let rhs = m.input("in2", 3);
            /// let multi_bitor = lhs | rhs;
            /// ```
            fn bitor(self, rhs: S) -> Self::Output {
                let lhs = self.internal_signal();
                let rhs = rhs.into().internal_signal();
                if !ptr::eq(lhs.module, rhs.module) {
                    panic!("Attempted to combine signals from different modules.");
                }
                if lhs.bit_width() != rhs.bit_width() {
                    panic!(
                        "Signals have different bit widths ({} and {}, respectively).",
                        lhs.bit_width(),
                        rhs.bit_width()
                    );
                }
                lhs.context.signal_arena.alloc(InternalSignal {
                    context: lhs.context,
                    module: lhs.module,

                    data: SignalData::SimpleBinOp {
                        lhs,
                        rhs,
                        op: SimpleBinOp::BitOr,
                        bit_width: lhs.bit_width(),
                    },
                })
            }
        }

        impl<'a, S: Into<&'a dyn Signal<'a>>> BitXor<S> for &'a $t {
            type Output = &'a dyn Signal<'a>;

            /// Combines two `Signal`s, producing a new `Signal` whose bits represent the bitwise `^` of each of the bits of the original two `Signal`s.
            ///
            /// # Panics
            ///
            /// Panics if `lhs` and `rhs` belong to different [`Module`]s, or if the bit widths of `lhs` and `rhs` aren't equal.
            ///
            /// # Examples
            ///
            /// ```
            /// use kaze::*;
            ///
            /// let c = Context::new();
            ///
            /// let m = c.module("m", "MyModule");
            ///
            /// let lhs = m.low();
            /// let rhs = m.high();
            /// let single_bitxor = lhs ^ rhs;
            ///
            /// let lhs = m.input("in1", 3);
            /// let rhs = m.input("in2", 3);
            /// let multi_bitxor = lhs ^ rhs;
            /// ```
            fn bitxor(self, rhs: S) -> Self::Output {
                let lhs = self.internal_signal();
                let rhs = rhs.into().internal_signal();
                if !ptr::eq(lhs.module, rhs.module) {
                    panic!("Attempted to combine signals from different modules.");
                }
                if lhs.bit_width() != rhs.bit_width() {
                    panic!(
                        "Signals have different bit widths ({} and {}, respectively).",
                        lhs.bit_width(),
                        rhs.bit_width()
                    );
                }
                lhs.context.signal_arena.alloc(InternalSignal {
                    context: lhs.context,
                    module: lhs.module,

                    data: SignalData::SimpleBinOp {
                        lhs,
                        rhs,
                        op: SimpleBinOp::BitXor,
                        bit_width: lhs.bit_width(),
                    },
                })
            }
        }

        impl<'a, S: Into<&'a dyn Signal<'a>>> Mul<S> for &'a $t {
            type Output = &'a dyn Signal<'a>;

            /// Combines two `Signal`s, producing a new `Signal` that represents the unsigned product of the original two `Signal`s.
            ///
            /// The product's `bit_width` is equal to `self.bit_width() + rhs.bit_width()`.
            ///
            /// # Panics
            ///
            /// Panics if `lhs` and `rhs` belong to different [`Module`]s, or if `self.bit_width() + rhs.bit_width()` is greater than [`MAX_SIGNAL_BIT_WIDTH`].
            ///
            /// # Examples
            ///
            /// ```
            /// use kaze::*;
            ///
            /// let c = Context::new();
            ///
            /// let m = c.module("m", "MyModule");
            ///
            /// let lhs = m.lit(4u32, 3);
            /// let rhs = m.lit(5u32, 4);
            /// let sum = lhs * rhs; // Equivalent to m.lit(20u32, 7)
            /// ```
            fn mul(self, rhs: S) -> Self::Output {
                let lhs = self.internal_signal();
                let rhs = rhs.into().internal_signal();
                if !ptr::eq(lhs.module, rhs.module) {
                    panic!("Attempted to combine signals from different modules.");
                }
                let bit_width = lhs.bit_width() + rhs.bit_width();
                if bit_width > MAX_SIGNAL_BIT_WIDTH {
                    panic!("Attempted to multiply a {}-bit with a {}-bit signal, but this would result in a bit width of {}, which is greater than the maximum signal bit width of {} bit(s).", self.bit_width(), rhs.bit_width(), bit_width, MAX_SIGNAL_BIT_WIDTH);
                }
                lhs.context.signal_arena.alloc(InternalSignal {
                    context: lhs.context,
                    module: lhs.module,

                    data: SignalData::Mul {
                        lhs,
                        rhs,
                        bit_width,
                    },
                })
            }
        }

        impl<'a> Not for &'a $t {
            type Output = &'a dyn Signal<'a>;

            /// Produces a new `Signal` whose bits represent the bitwise `!` of each of the bits of the original `Signal`.
            ///
            /// # Examples
            ///
            /// ```
            /// use kaze::*;
            ///
            /// let c = Context::new();
            ///
            /// let m = c.module("m", "MyModule");
            ///
            /// let input1 = m.input("input1", 1);
            /// let single_not = !input1;
            ///
            /// let input2 = m.input("input2", 6);
            /// let multi_not = !input2;
            /// ```
            fn not(self) -> Self::Output {
                let s = self.internal_signal();
                s.context.signal_arena.alloc(InternalSignal {
                    context: s.context,
                    module: s.module,

                    data: SignalData::UnOp {
                        source: s,
                        op: UnOp::Not,
                        bit_width: self.bit_width(),
                    },
                })
            }
        }

        impl<'a, S: Into<&'a dyn Signal<'a>>> Shl<S> for &'a $t {
            type Output = &'a dyn Signal<'a>;

            /// Combines two `Signal`s, producing a new `Signal` that represents `self` logically shifted left by `rhs` bits.
            ///
            /// The result is truncated to `self`'s `bit_width`. If `rhs` specifies a value that's greater than or equal to `self`'s `bit_width`, the resulting value will be zero.
            ///
            /// # Panics
            ///
            /// Panics if `lhs` and `rhs` belong to different [`Module`]s.
            ///
            /// # Examples
            ///
            /// ```
            /// use kaze::*;
            ///
            /// let c = Context::new();
            ///
            /// let m = c.module("m", "MyModule");
            ///
            /// let lhs = m.lit(3u32, 32);
            /// let rhs = m.lit(2u32, 2);
            /// let shifted = lhs << rhs; // Equivalent to m.lit(12u32, 32)
            /// ```
            fn shl(self, rhs: S) -> Self::Output {
                let lhs = self.internal_signal();
                let rhs = rhs.into().internal_signal();
                if !ptr::eq(lhs.module, rhs.module) {
                    panic!("Attempted to combine signals from different modules.");
                }
                lhs.context.signal_arena.alloc(InternalSignal {
                    context: lhs.context,
                    module: lhs.module,

                    data: SignalData::ShiftBinOp {
                        lhs,
                        rhs,
                        op: ShiftBinOp::Shl,
                        bit_width: lhs.bit_width(),
                    },
                })
            }
        }

        impl<'a, S: Into<&'a dyn Signal<'a>>> Shr<S> for &'a $t {
            type Output = &'a dyn Signal<'a>;

            /// Combines two `Signal`s, producing a new `Signal` that represents `self` logically shifted right by `rhs` bits.
            ///
            /// The result is truncated to `self`'s `bit_width`. If `rhs` specifies a value that's greater than or equal to `self`'s `bit_width`, the resulting value will be zero.
            ///
            /// # Panics
            ///
            /// Panics if `lhs` and `rhs` belong to different [`Module`]s.
            ///
            /// # Examples
            ///
            /// ```
            /// use kaze::*;
            ///
            /// let c = Context::new();
            ///
            /// let m = c.module("m", "MyModule");
            ///
            /// let lhs = m.lit(12u32, 32);
            /// let rhs = m.lit(2u32, 2);
            /// let shifted = lhs >> rhs; // Equivalent to m.lit(3u32, 32)
            /// ```
            fn shr(self, rhs: S) -> Self::Output {
                let lhs = self.internal_signal();
                let rhs = rhs.into().internal_signal();
                if !ptr::eq(lhs.module, rhs.module) {
                    panic!("Attempted to combine signals from different modules.");
                }
                lhs.context.signal_arena.alloc(InternalSignal {
                    context: lhs.context,
                    module: lhs.module,

                    data: SignalData::ShiftBinOp {
                        lhs,
                        rhs,
                        op: ShiftBinOp::Shr,
                        bit_width: lhs.bit_width(),
                    },
                })
            }
        }

        impl<'a, S: Into<&'a dyn Signal<'a>>> Sub<S> for &'a $t {
            type Output = &'a dyn Signal<'a>;

            /// Combines two `Signal`s, producing a new `Signal` that represents the difference of the original two `Signal`s.
            ///
            /// The difference is truncated to the `Signal`'s `bit_width`.
            ///
            /// # Panics
            ///
            /// Panics if `lhs` and `rhs` belong to different [`Module`]s, or if the bit widths of `lhs` and `rhs` aren't equal.
            ///
            /// # Examples
            ///
            /// ```
            /// use kaze::*;
            ///
            /// let c = Context::new();
            ///
            /// let m = c.module("m", "MyModule");
            ///
            /// let lhs = m.lit(3u32, 32);
            /// let rhs = m.lit(2u32, 32);
            /// let difference = lhs - rhs; // Equivalent to m.lit(1u32, 32)
            /// ```
            fn sub(self, rhs: S) -> Self::Output {
                let lhs = self.internal_signal();
                let rhs = rhs.into().internal_signal();
                if !ptr::eq(lhs.module, rhs.module) {
                    panic!("Attempted to combine signals from different modules.");
                }
                if lhs.bit_width() != rhs.bit_width() {
                    panic!(
                        "Signals have different bit widths ({} and {}, respectively).",
                        lhs.bit_width(),
                        rhs.bit_width()
                    );
                }
                lhs.context.signal_arena.alloc(InternalSignal {
                    context: lhs.context,
                    module: lhs.module,

                    data: SignalData::AdditiveBinOp {
                        lhs,
                        rhs,
                        op: AdditiveBinOp::Sub,
                        bit_width: self.bit_width(),
                    },
                })
            }
        }

        impl<'a, S: Into<String>> RegNext<'a, S> for &'a $t {
            fn reg_next(self, name: S) -> &'a dyn Signal<'a> {
                let s = self.internal_signal();
                let reg = s.module.reg(name, s.bit_width());
                reg.drive_next(s);
                reg
            }
        }

        impl<'a, S: Into<String>, C: Into<Constant>> RegNextWithDefault<'a, S, C> for &'a $t {
            fn reg_next_with_default(
                self,
                name: S,
                default_value: C,
            ) -> &'a dyn Signal<'a> {
                let s = self.internal_signal();
                let reg = s.module.reg(name, s.bit_width());
                reg.default_value(default_value);
                reg.drive_next(s);
                reg
            }
        }
    )*);
}

// TODO: Move extension stuff?
use super::module::{Input, Output};
use super::register::Register;
impl_extensions! { dyn Signal<'a>, Input<'a>, Output<'a>, Register<'a> }

impl<'a, T: GetInternalSignal<'a>> Signal<'a> for T {}

impl<'a, T: GetInternalSignal<'a>> From<&'a T> for &'a dyn Signal<'a> {
    fn from(s: &'a T) -> &'a dyn Signal<'a> {
        s.internal_signal()
    }
}

pub trait RegNext<'a, S: Into<String>> {
    /// Creates a [`Signal`] that represents the same value as this [`Signal`], but delayed by one cycle.
    ///
    /// This is achieved by creating a new [`Register`] called `name`, and specifying this [`Signal`] as the next value for the [`Register`]. Note that no default value is provided for this [`Register`], so the returned [`Signal`]'s value is undefined until the first clock edge, and its value is not affected by its [`Module`]'s implicit reset. If a default value is desired, use [`reg_next_with_default`] instead.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let a = m.lit(true, 1);
    /// let a_delayed = a.reg_next("a_delayed");
    /// ```
    ///
    /// [`reg_next_with_default`]: Self::reg_next_with_default
    fn reg_next(self, name: S) -> &'a dyn Signal<'a>;
}

pub trait RegNextWithDefault<'a, S: Into<String>, C: Into<Constant>> {
    /// Creates a [`Signal`] that represents the same value as this [`Signal`], but delayed by one cycle, except when this [`Signal`]'s [`Module`]'s implicit reset is asserted, at which point it will represent `default_value`.
    ///
    /// This is achieved by creating a new [`Register`] called `name`, specifying `default_value` as its default value, and specifying this [`Signal`] as the next value for the [`Register`]. If a default value is not desired, use [`reg_next`] instead.
    ///
    /// # Panics
    ///
    /// Panics if the specified `value` doesn't fit into this [`Signal`]'s bit width.
    ///
    /// # Examples
    ///
    /// ```
    /// use kaze::*;
    ///
    /// let c = Context::new();
    ///
    /// let m = c.module("m", "MyModule");
    ///
    /// let a = m.lit(true, 1);
    /// let a_delayed = a.reg_next_with_default("a_delayed", false);
    /// ```
    ///
    /// [`reg_next`]: Self::reg_next
    fn reg_next_with_default(self, name: S, default_value: C) -> &'a dyn Signal<'a>;
}

#[cfg(test)]
mod tests {
    use crate::graph::*;

    #[test]
    #[should_panic(
        expected = "Attempted to take bit index 3 from a signal with a width of 3 bits. Bit indices must be in the range [0, 2] for a signal with a width of 3 bits."
    )]
    fn bit_index_oob_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i = m.input("i", 3);

        let _ = i.bit(0); // OK
        let _ = i.bit(1); // OK
        let _ = i.bit(2); // OK

        let _ = i.bit(3); // Panic, `index` too high
    }

    #[test]
    #[should_panic(
        expected = "Cannot specify a range of bits where the lower bound is greater than or equal to the number of bits in the source signal. The bounds must be in the range [0, 2] for a signal with a width of 3 bits, but a lower bound of 3 was given."
    )]
    fn bits_range_low_oob_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i = m.input("i", 3);

        // Panic
        let _ = i.bits(4, 3);
    }

    #[test]
    #[should_panic(
        expected = "Cannot specify a range of bits where the upper bound is greater than or equal to the number of bits in the source signal. The bounds must be in the range [0, 2] for a signal with a width of 3 bits, but an upper bound of 3 was given."
    )]
    fn bits_range_high_oob_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i = m.input("i", 3);

        // Panic
        let _ = i.bits(3, 2);
    }

    #[test]
    #[should_panic(
        expected = "Cannot specify a range of bits where the lower bound is greater than the upper bound."
    )]
    fn bits_range_low_gt_high_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i = m.input("i", 3);

        // Panic
        let _ = i.bits(0, 1);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to repeat a 1-bit signal 0 times, but this would result in a bit width of 0, which is less than the minimal signal bit width of 1 bit(s)."
    )]
    fn repeat_count_zero_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i = m.input("i", 1);

        // Panic
        let _ = i.repeat(0);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to repeat a 1-bit signal 129 times, but this would result in a bit width of 129, which is greater than the maximum signal bit width of 128 bit(s)."
    )]
    fn repeat_count_oob_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i = m.input("i", 1);

        // Panic
        let _ = i.repeat(129);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn concat_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.concat(i2);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to concatenate signals with 128 bit(s) and 1 bit(s) respectively, but this would result in a bit width of 129, which is greater than the maximum signal bit width of 128 bit(s)."
    )]
    fn concat_oob_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("i1", 128);
        let i2 = m.input("i2", 1);

        // Panic
        let _ = i1.concat(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn eq_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.eq(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn eq_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.eq(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn ne_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.ne(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn ne_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.ne(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn lt_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.lt(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn lt_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.lt(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn le_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.le(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn le_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.le(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn gt_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.gt(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn gt_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.gt(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn ge_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.ge(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn ge_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.ge(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn lt_signed_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.lt_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn lt_signed_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.lt_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Cannot perform signed comparison of 1-bit signals.")]
    fn lt_signed_bit_width_1_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 1);
        let i2 = m.input("b", 1);

        // Panic
        let _ = i1.lt_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn le_signed_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.le_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn le_signed_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.le_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Cannot perform signed comparison of 1-bit signals.")]
    fn le_signed_bit_width_1_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 1);
        let i2 = m.input("b", 1);

        // Panic
        let _ = i1.le_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn gt_signed_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.gt_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn gt_signed_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.gt_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Cannot perform signed comparison of 1-bit signals.")]
    fn gt_signed_bit_width_1_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 1);
        let i2 = m.input("b", 1);

        // Panic
        let _ = i1.gt_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn ge_signed_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.ge_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn ge_signed_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1.ge_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Cannot perform signed comparison of 1-bit signals.")]
    fn ge_signed_bit_width_1_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 1);
        let i2 = m.input("b", 1);

        // Panic
        let _ = i1.ge_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn shr_arithmetic_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.shr_arithmetic(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn mul_signed_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1.mul_signed(i2);
    }

    #[test]
    #[should_panic(
        expected = "Attempted to multiply a 128-bit with a 1-bit signal, but this would result in a bit width of 129, which is greater than the maximum signal bit width of 128 bit(s)."
    )]
    fn mul_signed_oob_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 128);
        let i2 = m.input("b", 1);

        // Panic
        let _ = i1.mul_signed(i2);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn mux_cond_separate_module_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(false, 1);

        let b = c.module("b", "B");
        let l2 = b.lit(32u8, 8);
        let l3 = b.lit(32u8, 8);

        // Panic
        let _ = l1.mux(l2, l3);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn mux_when_true_separate_module_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(32u8, 8);

        let b = c.module("b", "B");
        let l2 = b.lit(true, 1);
        let l3 = b.lit(32u8, 8);

        // Panic
        let _ = l2.mux(l1, l3);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn mux_when_false_separate_module_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(32u8, 8);

        let b = c.module("b", "B");
        let l2 = b.lit(true, 1);
        let l3 = b.lit(32u8, 8);

        // Panic
        let _ = l2.mux(l3, l1);
    }

    #[test]
    #[should_panic(expected = "Multiplexer conditionals can only be 1 bit wide.")]
    fn mux_cond_bit_width_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(2u8, 2);
        let l2 = a.lit(32u8, 8);
        let l3 = a.lit(32u8, 8);

        // Panic
        let _ = l1.mux(l2, l3);
    }

    #[test]
    #[should_panic(
        expected = "Cannot multiplex signals with different bit widths (3 and 5, respectively)."
    )]
    fn mux_true_false_bit_width_error() {
        let c = Context::new();

        let a = c.module("a", "A");
        let l1 = a.lit(false, 1);
        let l2 = a.lit(3u8, 3);
        let l3 = a.lit(3u8, 5);

        // Panic
        let _ = a.mux(l1, l2, l3);
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn add_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1 + i2;
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn add_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1 + i2;
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn bitand_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1 & i2;
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn bitand_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1 & i2;
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn bitor_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1 | i2;
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn bitor_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1 | i2;
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn bitxor_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1 ^ i2;
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn bitxor_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1 ^ i2;
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn mul_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1 * i2;
    }

    #[test]
    #[should_panic(
        expected = "Attempted to multiply a 128-bit with a 1-bit signal, but this would result in a bit width of 129, which is greater than the maximum signal bit width of 128 bit(s)."
    )]
    fn mul_oob_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 128);
        let i2 = m.input("b", 1);

        // Panic
        let _ = i1 * i2;
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn shl_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1 << i2;
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn shr_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1 >> i2;
    }

    #[test]
    #[should_panic(expected = "Attempted to combine signals from different modules.")]
    fn sub_separate_module_error() {
        let c = Context::new();

        let m1 = c.module("a", "A");
        let i1 = m1.input("a", 1);

        let m2 = c.module("b", "B");
        let i2 = m2.high();

        // Panic
        let _ = i1 - i2;
    }

    #[test]
    #[should_panic(expected = "Signals have different bit widths (3 and 5, respectively).")]
    fn sub_incompatible_bit_widths_error() {
        let c = Context::new();

        let m = c.module("a", "A");
        let i1 = m.input("a", 3);
        let i2 = m.input("b", 5);

        // Panic
        let _ = i1 - i2;
    }
}


================================================
FILE: kaze/src/graph/sugar.rs
================================================
use super::signal::*;

/// **UNSTABLE:** Provides a convenient way to write conditional combinational logic.
///
/// # Panics
///
/// Since this construct wraps the returned values with [`Signal::mux`], any panic conditions from that method apply to the generated code as well.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let p = Context::new();
///
/// let m = p.module("m", "MyModule");
/// let i = m.input("i", 1);
/// let invert = m.input("invert", 1);
/// let o = if_(invert, {
///     !i
/// }).else_({
///     i
/// });
/// m.output("o", o);
/// ```
// TODO: Can we constrain T more than this to make sure it's only a supported type?
pub fn if_<'a, T>(cond: &'a dyn Signal<'a>, when_true: T) -> If<'a, T> {
    If::new(cond, when_true)
}

#[doc(hidden)]
pub struct If<'a, T> {
    cond: &'a dyn Signal<'a>,
    when_true: T,
}

impl<'a, T> If<'a, T> {
    fn new(cond: &'a dyn Signal<'a>, when_true: T) -> If<'a, T> {
        If { cond, when_true }
    }

    pub fn else_if(self, cond: &'a dyn Signal<'a>, when_true: T) -> ElseIf<'a, T> {
        ElseIf {
            parent: ElseIfParent::If(self),
            cond,
            when_true,
        }
    }
}

impl<'a, T: Into<&'a dyn Signal<'a>>> If<'a, T> {
    pub fn else_<F: Into<&'a dyn Signal<'a>>>(self, when_false: F) -> &'a dyn Signal<'a> {
        self.cond.mux(self.when_true.into(), when_false.into())
    }
}

macro_rules! replace_tt { ($t:tt, $($i:tt)*) => { $($i)* } }

macro_rules! generate_if {
    (($($number: tt, $t: tt, $f: tt),*)) => {
        impl<'a, $($t: Into<&'a dyn Signal<'a>>),*,> If<'a, ($($t),*,)> {
            pub fn else_<$($f: Into<&'a dyn Signal<'a>>),*,>(self, when_false: ($($f),*,)) -> ($(&'a replace_tt!($number, dyn Signal<'a>)),*,) {
                (
                    $(self.cond.mux(self.when_true.$number.into(), when_false.$number.into())),*,
                )
            }
        }
    };
}

generate_if!((0, T0, F0));
generate_if!((0, T0, F0, 1, T1, F1));
generate_if!((0, T0, F0, 1, T1, F1, 2, T2, F2));
generate_if!((0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3));
generate_if!((0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4));
generate_if!((0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5));
generate_if!((0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6));
generate_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7
));
generate_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7, 8, T8,
    F8
));
generate_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7, 8, T8,
    F8, 9, T9, F9
));
generate_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7, 8, T8,
    F8, 9, T9, F9, 10, T10, F10
));
generate_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7, 8, T8,
    F8, 9, T9, F9, 10, T10, F10, 11, T11, F11
));

enum ElseIfParent<'a, T> {
    If(If<'a, T>),
    ElseIf(Box<ElseIf<'a, T>>),
}

#[doc(hidden)]
pub struct ElseIf<'a, T> {
    parent: ElseIfParent<'a, T>,
    cond: &'a dyn Signal<'a>,
    when_true: T,
}

impl<'a, T> ElseIf<'a, T> {
    pub fn else_if(self, cond: &'a dyn Signal<'a>, when_true: T) -> ElseIf<'a, T> {
        ElseIf {
            parent: ElseIfParent::ElseIf(Box::new(self)),
            cond,
            when_true,
        }
    }
}

impl<'a, T: Into<&'a dyn Signal<'a>>> ElseIf<'a, T> {
    pub fn else_<F: Into<&'a dyn Signal<'a>>>(self, when_false: F) -> &'a dyn Signal<'a> {
        let ret = self.cond.mux(self.when_true.into(), when_false.into());
        match self.parent {
            ElseIfParent::If(parent) => parent.else_(ret),
            ElseIfParent::ElseIf(parent) => parent.else_(ret),
        }
    }
}

macro_rules! generate_else_if {
    (($($number: tt, $t: tt, $f: tt),*)) => {
        impl<'a, $($t: Into<&'a dyn Signal<'a>>),*,> ElseIf<'a, ($($t),*,)> {
            pub fn else_<$($f: Into<&'a dyn Signal<'a>>),*,>(self, when_false: ($($f),*,)) -> ($(&'a replace_tt!($number, dyn Signal<'a>)),*,) {
                let ret = (
                    $(self.cond.mux(self.when_true.$number.into(), when_false.$number.into())),*,
                );
                match self.parent {
                    ElseIfParent::If(parent) => parent.else_(ret),
                    ElseIfParent::ElseIf(parent) => parent.else_(ret),
                }
            }
        }
    };
}

generate_else_if!((0, T0, F0));
generate_else_if!((0, T0, F0, 1, T1, F1));
generate_else_if!((0, T0, F0, 1, T1, F1, 2, T2, F2));
generate_else_if!((0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3));
generate_else_if!((0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4));
generate_else_if!((0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5));
generate_else_if!((0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6));
generate_else_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7
));
generate_else_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7, 8, T8,
    F8
));
generate_else_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7, 8, T8,
    F8, 9, T9, F9
));
generate_else_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7, 8, T8,
    F8, 9, T9, F9, 10, T10, F10
));
generate_else_if!((
    0, T0, F0, 1, T1, F1, 2, T2, F2, 3, T3, F3, 4, T4, F4, 5, T5, F5, 6, T6, F6, 7, T7, F7, 8, T8,
    F8, 9, T9, F9, 10, T10, F10, 11, T11, F11
));


================================================
FILE: kaze/src/graph.rs
================================================
mod constant;
mod context;
pub(crate) mod internal_signal;
mod mem;
mod module;
mod register;
mod signal;
mod sugar;

pub use constant::*;
pub use context::*;
pub use mem::*;
pub use module::*;
pub use register::*;
pub use signal::*;
pub use sugar::*;


================================================
FILE: kaze/src/lib.rs
================================================
//! An [HDL](https://en.wikipedia.org/wiki/Hardware_description_language) embedded in [Rust](https://www.rust-lang.org/).
//!
//! kaze provides an API to describe [`Module`]s composed of [`Signal`]s, which can then be used to generate [Rust simulator code](sim::generate) or [Verilog modules](verilog::generate).
//!
//! kaze's API is designed to be as minimal as possible while still being expressive.
//! It's designed to prevent the user from being able to describe buggy or incorrect hardware as much as possible.
//! This enables a user to hack on designs fearlessly, while the API and generators ensure that these designs are sound.
//!
//! # Usage
//!
//! ```toml
//! [dependencies]
//! kaze = "0.1"
//! ```
//!
//! # Examples
//!
//! ```rust
//! # fn main() -> std::io::Result<()> {
//! use kaze::*;
//!
//! // Create a context, which will contain our module(s)
//! let p = Context::new();
//!
//! // Create a module
//! let inverter = p.module("inverter", "Inverter");
//! let i = inverter.input("i", 1); // 1-bit input
//! inverter.output("o", !i); // Output inverted input
//!
//! // Generate Rust simulator code
//! sim::generate(inverter, sim::GenerationOptions::default(), std::io::stdout())?;
//!
//! // Generate Verilog code
//! //verilog::generate(inverter, std::io::stdout())?;
//! # Ok(())
//! # }
//! ```

// Must be kept up-to-date with version in Cargo.toml
#![doc(html_root_url = "https://docs.rs/kaze/0.1.19")]

mod code_writer;
mod graph;
pub mod runtime;
pub mod sim;
mod state_elements;
mod validation;
pub mod verilog;

pub use graph::*;


================================================
FILE: kaze/src/runtime/tracing/vcd.rs
================================================
//! [VCD](https://en.wikipedia.org/wiki/Value_change_dump) format tracing implementation.

extern crate vcd;

use super::*;

use std::io;

pub enum TimeScaleUnit {
    S,
    Ms,
    Us,
    Ns,
    Ps,
    Fs,
}

impl From<TimeScaleUnit> for vcd::TimescaleUnit {
    fn from(time_scale_unit: TimeScaleUnit) -> Self {
        match time_scale_unit {
            TimeScaleUnit::S => vcd::TimescaleUnit::S,
            TimeScaleUnit::Ms => vcd::TimescaleUnit::MS,
            TimeScaleUnit::Us => vcd::TimescaleUnit::US,
            TimeScaleUnit::Ns => vcd::TimescaleUnit::NS,
            TimeScaleUnit::Ps => vcd::TimescaleUnit::PS,
            TimeScaleUnit::Fs => vcd::TimescaleUnit::FS,
        }
    }
}

pub struct VcdTrace<W: io::Write> {
    module_hierarchy_depth: u32,

    signals: Vec<VcdTraceSignal>,

    w: vcd::Writer<W>,
}

impl<W: io::Write> VcdTrace<W> {
    pub fn new(w: W, time_scale: u32, time_scale_unit: TimeScaleUnit) -> io::Result<VcdTrace<W>> {
        let mut w = vcd::Writer::new(w);

        w.timescale(time_scale, time_scale_unit.into())?;

        Ok(VcdTrace {
            module_hierarchy_depth: 0,

            signals: Vec::new(),

            w,
        })
    }
}

impl<W: io::Write> Trace for VcdTrace<W> {
    type SignalId = usize;

    fn push_module(&mut self, name: &'static str) -> io::Result<()> {
        self.w.add_module(name)?;

        self.module_hierarchy_depth += 1;

        Ok(())
    }

    fn pop_module(&mut self) -> io::Result<()> {
        self.w.upscope()?;

        self.module_hierarchy_depth -= 1;

        if self.module_hierarchy_depth == 0 {
            self.w.enddefinitions()?;
        }

        Ok(())
    }

    fn add_signal(
        &mut self,
        name: &'static str,
        bit_width: u32,
        type_: TraceValueType,
    ) -> io::Result<Self::SignalId> {
        let ret = self.signals.len();

        self.signals.push(VcdTraceSignal {
            bit_width,
            type_,
            // TODO: Is wire the right construct here always?
            id: self.w.add_wire(bit_width, name)?,
        });

        Ok(ret)
    }

    fn update_time_stamp(&mut self, time_stamp: u64) -> io::Result<()> {
        self.w.timestamp(time_stamp)
    }

    fn update_signal(&mut self, signal_id: &Self::SignalId, value: TraceValue) -> io::Result<()> {
        // TODO: Type check incoming value!
        let signal = &self.signals[*signal_id];

        if let TraceValueType::Bool = signal.type_ {
            self.w.change_scalar(
                signal.id,
                match value {
                    TraceValue::Bool(value) => value,
                    TraceValue::U32(_) | TraceValue::U64(_) | TraceValue::U128(_) => unreachable!(),
                },
            )?;
        } else {
            let value = match value {
                TraceValue::Bool(_) => unreachable!(),
                TraceValue::U32(value) => value as _,
                TraceValue::U64(value) => value as _,
                TraceValue::U128(value) => value,
            };
            let mut scalar_values = [vcd::Value::V0; 128];
            for i in 0..signal.bit_width as usize {
                scalar_values[i] = ((value >> (signal.bit_width as usize - 1 - i)) & 1 != 0).into();
            }
            self.w
                .change_vector(signal.id, &scalar_values[0..signal.bit_width as usize])?;
        }

        Ok(())
    }
}

struct VcdTraceSignal {
    bit_width: u32,
    type_: TraceValueType,
    id: vcd::IdCode,
}


================================================
FILE: kaze/src/runtime/tracing.rs
================================================
//! Rust simulator runtime dependencies for tracing.

pub mod vcd;

use std::io;

// TODO: Do we want to re-use graph::Constant for this? They're equivalent but currently distinct in their usage, so I'm not sure it's the right API design decision.
#[derive(Debug, Eq, PartialEq)]
pub enum TraceValue {
    /// Contains a boolean value
    Bool(bool),
    /// Contains an unsigned, 32-bit value
    U32(u32),
    /// Contains an unsigned, 64-bit value
    U64(u64),
    /// Contains an unsigned, 128-bit value
    U128(u128),
}

#[derive(Debug, Eq, PartialEq)]
pub enum TraceValueType {
    Bool,
    U32,
    U64,
    U128,
}

impl TraceValueType {
    pub(crate) fn from_bit_width(bit_width: u32) -> TraceValueType {
        if bit_width == 1 {
            TraceValueType::Bool
        } else if bit_width <= 32 {
            TraceValueType::U32
        } else if bit_width <= 64 {
            TraceValueType::U64
        } else if bit_width <= 128 {
            TraceValueType::U128
        } else {
            unreachable!()
        }
    }
}

pub trait Trace {
    type SignalId;

    fn push_module(&mut self, name: &'static str) -> io::Result<()>;
    fn pop_module(&mut self) -> io::Result<()>;
    fn add_signal(
        &mut self,
        name: &'static str,
        bit_width: u32,
        type_: TraceValueType,
    ) -> io::Result<Self::SignalId>;

    fn update_time_stamp(&mut self, time_stamp: u64) -> io::Result<()>;
    fn update_signal(&mut self, signal_id: &Self::SignalId, value: TraceValue) -> io::Result<()>;
}


================================================
FILE: kaze/src/runtime.rs
================================================
//! Rust simulator runtime dependencies. These are only required for simulators with tracing enabled.

pub mod tracing;


================================================
FILE: kaze/src/sim/compiler.rs
================================================
use super::ir::*;

use crate::graph::internal_signal;
use crate::state_elements::*;

use typed_arena::Arena;

use std::collections::HashMap;

// TODO: Can we merge the context and expr_arena lifetimes?
pub(super) struct Compiler<'graph, 'context, 'expr_arena> {
    state_elements: &'context StateElements<'graph>,
    signal_reference_counts:
        &'context HashMap<&'graph internal_signal::InternalSignal<'graph>, u32>,
    expr_arena: &'expr_arena Arena<Expr<'expr_arena>>,

    signal_exprs:
        HashMap<&'graph internal_signal::InternalSignal<'graph>, &'expr_arena Expr<'expr_arena>>,
}

impl<'graph, 'context, 'expr_arena> Compiler<'graph, 'context, 'expr_arena> {
    pub fn new(
        state_elements: &'context StateElements<'graph>,
        signal_reference_counts: &'context HashMap<
            &'graph internal_signal::InternalSignal<'graph>,
            u32,
        >,
        expr_arena: &'expr_arena Arena<Expr<'expr_arena>>,
    ) -> Compiler<'graph, 'context, 'expr_arena> {
        Compiler {
            state_elements,
            signal_reference_counts,
            expr_arena,

            signal_exprs: HashMap::new(),
        }
    }

    pub fn compile_signal(
        &mut self,
        signal: &'graph internal_signal::InternalSignal<'graph>,
        a: &mut AssignmentContext<'expr_arena>,
    ) -> &'expr_arena Expr<'expr_arena> {
        enum Frame<'graph> {
            Enter(&'graph internal_signal::InternalSignal<'graph>),
            Leave(&'graph internal_signal::InternalSignal<'graph>),
        }

        let mut frames = Vec::new();
        frames.push(Frame::Enter(signal));

        let mut results = Vec::new();

        while let Some(frame) = frames.pop() {
            if let Some((key, mut expr)) = match frame {
                Frame::Enter(signal) => {
                    let key = signal;
                    if let Some(expr) = self.signal_exprs.get(&key) {
                        results.push(*expr);
                        continue;
                    }

                    match signal.data {
                        internal_signal::SignalData::Lit {
                            ref value,
                            bit_width,
                        } => Some((key, Expr::from_constant(value, bit_width, &self.expr_arena))),

                        internal_signal::SignalData::Input { data } => {
                            if let Some(driven_value) = data.driven_value.borrow().clone() {
                                frames.push(Frame::Enter(driven_value));
                                None
                            } else {
                                let bit_width = data.bit_width;
                                let target_type = ValueType::from_bit_width(bit_width);
                                let expr = self.expr_arena.alloc(Expr::Ref {
                                    name: data.name.clone(),
                                    scope: Scope::Member,
                                });
                                Some((key, self.gen_mask(expr, bit_width, target_type)))
                            }
                        }
                        internal_signal::SignalData::Output { data } => {
                            frames.push(Frame::Enter(data.source));
                            None
                        }

                        internal_signal::SignalData::Reg { .. } => Some((
                            key,
                            &*self.expr_arena.alloc(Expr::Ref {
                                name: self.state_elements.regs[&key].value_name.clone(),
                                scope: Scope::Member,
                            }),
                        )),

                        internal_signal::SignalData::UnOp { source, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(source));
                            None
                        }
                        internal_signal::SignalData::SimpleBinOp { lhs, rhs, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(lhs));
                            frames.push(Frame::Enter(rhs));
                            None
                        }
                        internal_signal::SignalData::AdditiveBinOp { lhs, rhs, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(lhs));
                            frames.push(Frame::Enter(rhs));
                            None
                        }
                        internal_signal::SignalData::ComparisonBinOp { lhs, rhs, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(lhs));
                            frames.push(Frame::Enter(rhs));
                            None
                        }
                        internal_signal::SignalData::ShiftBinOp { lhs, rhs, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(lhs));
                            frames.push(Frame::Enter(rhs));
                            None
                        }

                        internal_signal::SignalData::Mul { lhs, rhs, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(lhs));
                            frames.push(Frame::Enter(rhs));
                            None
                        }
                        internal_signal::SignalData::MulSigned { lhs, rhs, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(lhs));
                            frames.push(Frame::Enter(rhs));
                            None
                        }

                        internal_signal::SignalData::Bits { source, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(source));
                            None
                        }

                        internal_signal::SignalData::Repeat { source, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(source));
                            None
                        }
                        internal_signal::SignalData::Concat { lhs, rhs, .. } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(lhs));
                            frames.push(Frame::Enter(rhs));
                            None
                        }

                        internal_signal::SignalData::Mux {
                            cond,
                            when_true,
                            when_false,
                            ..
                        } => {
                            frames.push(Frame::Leave(signal));
                            frames.push(Frame::Enter(cond));
                            frames.push(Frame::Enter(when_true));
                            frames.push(Frame::Enter(when_false));
                            None
                        }

                        internal_signal::SignalData::MemReadPortOutput {
                            mem,
                            address,
                            enable,
                        } => {
                            let mem = &self.state_elements.mems[&mem];
                            let read_signal_names = &mem.read_signal_names[&(address, enable)];
                            Some((
                                key,
                                &*self.expr_arena.alloc(Expr::Ref {
                                    name: read_signal_names.value_name.clone(),
                                    scope: Scope::Member,
                                }),
                            ))
                        }
                    }
                }
                Frame::Leave(signal) => {
                    let key = signal;

                    match signal.data {
                        internal_signal::SignalData::Lit { .. } => unreachable!(),

                        internal_signal::SignalData::Input { .. } => unreachable!(),
                        internal_signal::SignalData::Output { .. } => unreachable!(),

                        internal_signal::SignalData::Reg { .. } => unreachable!(),

                        internal_signal::SignalData::UnOp { op, bit_width, .. } => {
                            let expr = results.pop().unwrap();
                            let expr = self.expr_arena.alloc(Expr::UnOp {
                                source: expr,
                                op: match op {
                                    internal_signal::UnOp::Not => UnOp::Not,
                                },
                            });

                            let target_type = ValueType::from_bit_width(bit_width);
                            Some((key, self.gen_mask(expr, bit_width, target_type)))
                        }
                        internal_signal::SignalData::SimpleBinOp { op, .. } => {
                            let lhs = results.pop().unwrap();
                            let rhs = results.pop().unwrap();
                            Some((
                                key,
                                &*self.expr_arena.alloc(Expr::InfixBinOp {
                                    lhs,
                                    rhs,
                                    op: match op {
                                        internal_signal::SimpleBinOp::BitAnd => InfixBinOp::BitAnd,
                                        internal_signal::SimpleBinOp::BitOr => InfixBinOp::BitOr,
                                        internal_signal::SimpleBinOp::BitXor => InfixBinOp::BitXor,
                                    },
                                }),
                            ))
                        }
                        internal_signal::SignalData::AdditiveBinOp { lhs, op, .. } => {
                            let source_bit_width = lhs.bit_width();
                            let source_type = ValueType::from_bit_width(source_bit_width);
                            let lhs = results.pop().unwrap();
                            let rhs = results.pop().unwrap();
                            let op_input_type = match source_type {
                                ValueType::Bool => ValueType::U32,
                                _ => source_type,
                            };
                            let lhs = self.gen_cast(lhs, source_type, op_input_type);
                            let rhs = self.gen_cast(rhs, source_type, op_input_type);
                            let expr = self.expr_arena.alloc(Expr::UnaryMemberCall {
                                target: lhs,
                                name: match op {
                                    internal_signal::AdditiveBinOp::Add => "wrapping_add".into(),
                                    internal_signal::AdditiveBinOp::Sub => "wrapping_sub".into(),
                                },
                                arg: rhs,
                            });
                            let op_output_type = op_input_type;
                            let target_bit_width = signal.bit_width();
                            let target_type = ValueType::from_bit_width(target_bit_width);
                            let expr = self.gen_cast(expr, op_output_type, target_type);
                            Some((key, self.gen_mask(expr, target_bit_width, target_type)))
                        }
                        internal_signal::SignalData::ComparisonBinOp { lhs, op, .. } => {
                            let source_bit_width = lhs.bit_width();
                            let source_type = ValueType::from_bit_width(source_bit_width);
                            let mut lhs = results.pop().unwrap();
                            let mut rhs = results.pop().unwrap();
                            match op {
                                internal_signal::ComparisonBinOp::GreaterThanEqualSigned
                                | internal_signal::ComparisonBinOp::GreaterThanSigned
                                | internal_signal::ComparisonBinOp::LessThanEqualSigned
                                | internal_signal::ComparisonBinOp::LessThanSigned => {
                                    let source_type_signed = source_type.to_signed();
                                    lhs = self.gen_cast(lhs, source_type, source_type_signed);
                                    rhs = self.gen_cast(rhs, source_type, source_type_signed);
                                    lhs = self.gen_sign_extend_shifts(
                                        lhs,
                                        source_bit_width,
                                        source_type_signed,
                                    );
                                    rhs = self.gen_sign_extend_shifts(
                                        rhs,
                                        source_bit_width,
                                        source_type_signed,
                                    );
                                }
                                _ => (),
                            }
                            Some((
                                key,
                                &*self.expr_arena.alloc(Expr::InfixBinOp {
                                    lhs,
                                    rhs,
                                    op: match op {
                                        internal_signal::ComparisonBinOp::Equal => InfixBinOp::Equal,
                                        internal_signal::ComparisonBinOp::NotEqual => InfixBinOp::NotEqual,
                                        internal_signal::ComparisonBinOp::LessThan
                                        | internal_signal::ComparisonBinOp::LessThanSigned => {
                                            InfixBinOp::LessThan
                                        }
                                        internal_signal::ComparisonBinOp::LessThanEqual
                                        | internal_signal::ComparisonBinOp::LessThanEqualSigned => {
                                            InfixBinOp::LessThanEqual
                                        }
                                        internal_signal::ComparisonBinOp::GreaterThan
                                        | internal_signal::ComparisonBinOp::GreaterThanSigned => {
                                            InfixBinOp::GreaterThan
                                        }
                                        internal_signal::ComparisonBinOp::GreaterThanEqual
                                        | internal_signal::ComparisonBinOp::GreaterThanEqualSigned => {
                                            InfixBinOp::GreaterThanEqual
                                        }
                                    },
                                }),
                            ))
                        }
                        internal_signal::SignalData::ShiftBinOp {
                            lhs,
                            rhs,
                            op,
                            bit_width,
                        } => {
                            let lhs_source_bit_width = lhs.bit_width();
                            let lhs_source_type = ValueType::from_bit_width(lhs_source_bit_width);
                            let rhs_source_bit_width = rhs.bit_width();
                            let rhs_source_type = ValueType::from_bit_width(rhs_source_bit_width);
                            let lhs = results.pop().unwrap();
                            let rhs = results.pop().unwrap();
                            let lhs_op_input_type = match lhs_source_type {
                                ValueType::Bool => ValueType::U32,
                                _ => lhs_source_type,
                            };
                            let lhs = self.gen_cast(lhs, lhs_source_type, lhs_op_input_type);
                            let lhs = match op {
                                internal_signal::ShiftBinOp::Shl
                                | internal_signal::ShiftBinOp::Shr => lhs,
                                internal_signal::ShiftBinOp::ShrArithmetic => {
                                    let lhs_op_input_type_signed = lhs_op_input_type.to_signed();
                                    let lhs = self.gen_cast(
                                        lhs,
                                        lhs_op_input_type,
                                        lhs_op_input_type_signed,
                                    );
                                    self.gen_sign_extend_shifts(
                                        lhs,
                                        lhs_source_bit_width,
                                        lhs_op_input_type_signed,
                                    )
                                }
                            };
                            let rhs_op_input_type = match rhs_source_type {
                                ValueType::Bool => ValueType::U32,
                                _ => rhs_source_type,
                            };
                            let rhs = self.gen_cast(rhs, rhs_source_type, rhs_op_input_type);
                            let rhs = self.expr_arena.alloc(Expr::BinaryFunctionCall {
                                name: "std::cmp::min".into(),
                                lhs: rhs,
                                rhs: self.expr_arena.alloc(Expr::Constant {
                                    value: match rhs_op_input_type {
                                        ValueType::Bool
                                        | ValueType::I32
                                        | ValueType::I64
                                        | ValueType::I128 => unreachable!(),
                                        ValueType::U32 => Constant::U32(std::u32::MAX),
                                        ValueType::U64 => Constant::U64(std::u32::MAX as _),
                                        ValueType::U128 => Constant::U128(std::u32::MAX as _),
                                    },
                                }),
                            });
                            let rhs = self.gen_cast(rhs, lhs_op_input_type, ValueType::U32);
                            let expr = self.expr_arena.alloc(Expr::UnaryMemberCall {
                                target: lhs,
                                name: match op {
                                    internal_signal::ShiftBinOp::Shl => "checked_shl".into(),
                                    internal_signal::ShiftBinOp::Shr
                                    | internal_signal::ShiftBinOp::ShrArithmetic => {
                                        "checked_shr".into()
                                    }
                                },
                                arg: rhs,
                            });
                            let expr = self.expr_arena.alloc(Expr::UnaryMemberCall {
                                target: expr,
                                name: "unwrap_or".into(),
                                arg: match op {
                                    internal_signal::ShiftBinOp::Shl
                                    | internal_signal::ShiftBinOp::Shr => {
                                        self.expr_arena.alloc(Expr::Constant {
                                            value: match lhs_op_input_type {
                                                ValueType::Bool
                                                | ValueType::I32
                                                | ValueType::I64
                                                | ValueType::I128 => unreachable!(),
                                                ValueType::U32 => Constant::U32(0),
                                                ValueType::U64 => Constant::U64(0),
                                                ValueType::U128 => Constant::U128(0),
                                            },
                                        })
                                    }
                                    internal_signal::ShiftBinOp::ShrArithmetic => {
                                        self.expr_arena.alloc(Expr::InfixBinOp {
                                            lhs,
                                            rhs: self.expr_arena.alloc(Expr::Constant {
                                                value: Constant::U32(
                                                    lhs_op_input_type.bit_width() - 1,
                                                ),
                                            }),
                                            op: InfixBinOp::Shr,
                                        })
                                    }
                                },
                            });
                            let op_output_type = lhs_op_input_type;
                            let expr = match op {
                                internal_signal::ShiftBinOp::Shl
                                | internal_signal::ShiftBinOp::Shr => expr,
                                internal_signal::ShiftBinOp::ShrArithmetic => {
                                    let lhs_op_output_type_signed = op_output_type.to_signed();
                                    self.gen_cast(expr, lhs_op_output_type_signed, op_output_type)
                                }
                            };
                            let target_bit_width = bit_width;
                            let target_type = ValueType::from_bit_width(target_bit_width);
                            let expr = self.gen_cast(expr, op_output_type, target_type);
                            Some((key, self.gen_mask(expr, target_bit_width, target_type)))
                        }

                        internal_signal::SignalData::Mul {
                            lhs,
                            rhs,
                            bit_width,
                        } => {
                            let lhs_type = ValueType::from_bit_width(lhs.bit_width());
                            let rhs_type = ValueType::from_bit_width(rhs.bit_width());
                            let lhs = results.pop().unwrap();
                            let rhs = results.pop().unwrap();
                            let target_type = ValueType::from_bit_width(bit_width);
                            let lhs = self.gen_cast(lhs, lhs_type, target_type);
                            let rhs = self.gen_cast(rhs, rhs_type, target_type);
                            Some((
                                key,
                                &*self.expr_arena.alloc(Expr::InfixBinOp {
                                    lhs,
                                    rhs,
                                    op: InfixBinOp::Mul,
                                }),
                            ))
                        }
                        internal_signal::SignalData::MulSigned {
                            lhs,
                            rhs,
                            bit_width,
                        } => {
                            let lhs_bit_width = lhs.bit_width();
                            let rhs_bit_width = rhs.bit_width();
                            let lhs_type = ValueType::from_bit_width(lhs_bit_width);
                            let rhs_type = ValueType::from_bit_width(rhs_bit_width);
                            let lhs = results.pop().unwrap();
                            let rhs = results.pop().unwrap();
                            let target_bit_width = bit_width;
                            let target_type = ValueType::from_bit_width(target_bit_width);
                            let target_type_signed = target_type.to_signed();
                            let lhs = self.gen_cast(lhs, lhs_type, target_type_signed);
                            let rhs = self.gen_cast(rhs, rhs_type, target_type_signed);
                            let lhs =
                                self.gen_sign_extend_shifts(lhs, lhs_bit_width, target_type_signed);
                            let rhs =
                                self.gen_sign_extend_shifts(rhs, rhs_bit_width, target_type_signed);
                            let expr = self.expr_arena.alloc(Expr::InfixBinOp {
                                lhs,
                                rhs,
                                op: InfixBinOp::Mul,
                            });
                            let expr = self.gen_cast(expr, target_type_signed, target_type);
                            Some((key, self.gen_mask(expr, target_bit_width, target_type)))
                        }

                        internal_signal::SignalData::Bits {
                            source, range_low, ..
                        } => {
                            let expr = results.pop().unwrap();
                            let expr = self.gen_shift_right(expr, range_low);
                            let target_bit_width = signal.bit_width();
                            let target_type = ValueType::from_bit_width(target_bit_width);
                            let expr = self.gen_cast(
                                expr,
                                ValueType::from_bit_width(source.bit_width()),
                                target_type,
                            );
                            Some((key, self.gen_mask(expr, target_bit_width, target_type)))
                        }

                        internal_signal::SignalData::Repeat {
                            source,
                            count,
                            bit_width,
                        } => {
                            let expr = results.pop().unwrap();
                            let mut expr = self.gen_cast(
                                expr,
                                ValueType::from_bit_width(source.bit_width()),
                                ValueType::from_bit_width(bit_width),
                            );

                            if count > 1 {
                                let source_expr = a.gen_temp(expr);

                                for i in 1..count {
                                    let rhs =
                                        self.gen_shift_left(source_expr, i * source.bit_width());
Download .txt
gitextract_k8l9vxpv/

├── .gitignore
├── CHANGELOG.md
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── kaze/
│   ├── Cargo.toml
│   └── src/
│       ├── code_writer.rs
│       ├── graph/
│       │   ├── constant.rs
│       │   ├── context.rs
│       │   ├── internal_signal.rs
│       │   ├── mem.rs
│       │   ├── module.rs
│       │   ├── register.rs
│       │   ├── signal.rs
│       │   └── sugar.rs
│       ├── graph.rs
│       ├── lib.rs
│       ├── runtime/
│       │   ├── tracing/
│       │   │   └── vcd.rs
│       │   └── tracing.rs
│       ├── runtime.rs
│       ├── sim/
│       │   ├── compiler.rs
│       │   └── ir.rs
│       ├── sim.rs
│       ├── state_elements.rs
│       ├── validation.rs
│       ├── verilog/
│       │   ├── compiler.rs
│       │   └── ir.rs
│       └── verilog.rs
└── sim-tests/
    ├── Cargo.toml
    ├── build.rs
    └── src/
        └── lib.rs
Download .txt
SYMBOL INDEX (410 symbols across 21 files)

FILE: kaze/src/code_writer.rs
  type CodeWriter (line 3) | pub struct CodeWriter<W: Write> {
  function new (line 9) | pub fn new(w: W) -> CodeWriter<W> {
  function indent (line 13) | pub fn indent(&mut self) {
  function unindent (line 17) | pub fn unindent(&mut self) {
  function append_indent (line 24) | pub fn append_indent(&mut self) -> Result<()> {
  function append_newline (line 31) | pub fn append_newline(&mut self) -> Result<()> {
  function append (line 36) | pub fn append(&mut self, s: &str) -> Result<()> {
  function append_line (line 41) | pub fn append_line(&mut self, s: &str) -> Result<()> {

FILE: kaze/src/graph/constant.rs
  type Constant (line 21) | pub enum Constant {
    method required_bits (line 34) | pub(super) fn required_bits(&self) -> u32 {
    method numeric_value (line 43) | pub(crate) fn numeric_value(&self) -> u128 {
    method from (line 54) | fn from(value: bool) -> Self {
    method from (line 60) | fn from(value: u8) -> Self {
    method from (line 66) | fn from(value: u16) -> Self {
    method from (line 72) | fn from(value: u32) -> Self {
    method from (line 78) | fn from(value: u64) -> Self {
    method from (line 84) | fn from(value: u128) -> Self {

FILE: kaze/src/graph/context.rs
  type ModuleParent (line 11) | pub trait ModuleParent<'a> {
    method module (line 44) | fn module(&'a self, instance_name: impl Into<String>, name: impl Into<...
  type Context (line 62) | pub struct Context<'a> {
  function new (line 86) | pub fn new() -> Context<'a> {
  function module (line 105) | fn module(&'a self, instance_name: impl Into<String>, name: impl Into<St...
  function new_context_has_no_modules (line 121) | fn new_context_has_no_modules() {

FILE: kaze/src/graph/internal_signal.rs
  type InternalSignal (line 10) | pub struct InternalSignal<'a> {
  function bit_width (line 18) | pub fn bit_width(&'a self) -> u32 {
  function module_instance_name_prefix (line 44) | pub(crate) fn module_instance_name_prefix(&self) -> String {
  method hash (line 68) | fn hash<H: Hasher>(&self, state: &mut H) {
  method eq (line 74) | fn eq(&self, other: &Self) -> bool {
  type SignalData (line 79) | pub(crate) enum SignalData<'a> {
  type UnOp (line 169) | pub(crate) enum UnOp {
  type SimpleBinOp (line 174) | pub(crate) enum SimpleBinOp {
  type ComparisonBinOp (line 181) | pub(crate) enum ComparisonBinOp {
  type AdditiveBinOp (line 195) | pub(crate) enum AdditiveBinOp {
  type ShiftBinOp (line 201) | pub(crate) enum ShiftBinOp {
  type GetInternalSignal (line 207) | pub trait GetInternalSignal<'a> {
    method internal_signal (line 209) | fn internal_signal(&'a self) -> &'a InternalSignal<'a>;
  function internal_signal (line 213) | fn internal_signal(&'a self) -> &'a InternalSignal<'a> {

FILE: kaze/src/graph/mem.rs
  type Mem (line 40) | pub struct Mem<'a> {
  function initial_contents (line 90) | pub fn initial_contents<C: Clone + Into<Constant>>(&'a self, contents: &...
  function read_port (line 136) | pub fn read_port(
  function write_port (line 193) | pub fn write_port(
  method hash (line 221) | fn hash<H: Hasher>(&self, state: &mut H) {
  method eq (line 227) | fn eq(&self, other: &Self) -> bool {
  function initial_contents_already_specified_error (line 240) | fn initial_contents_already_specified_error() {
  function initial_contents_length_error (line 256) | fn initial_contents_length_error() {
  function initial_contents_element_bit_width_error (line 270) | fn initial_contents_element_bit_width_error() {
  function read_port_address_bit_width_error (line 284) | fn read_port_address_bit_width_error() {
  function read_port_enable_bit_width_error (line 298) | fn read_port_enable_bit_width_error() {
  function write_port_already_specified_error (line 312) | fn write_port_already_specified_error() {
  function write_port_address_bit_width_error (line 328) | fn write_port_address_bit_width_error() {
  function write_port_value_bit_width_error (line 342) | fn write_port_value_bit_width_error() {
  function write_port_enable_bit_width_error (line 356) | fn write_port_enable_bit_width_error() {

FILE: kaze/src/graph/module.rs
  type Module (line 32) | pub struct Module<'a> {
  function new (line 49) | pub(super) fn new(
  function lit (line 92) | pub fn lit(&'a self, value: impl Into<Constant>, bit_width: u32) -> &dyn...
  function low (line 134) | pub fn low(&'a self) -> &dyn Signal<'a> {
  function high (line 153) | pub fn high(&'a self) -> &dyn Signal<'a> {
  function input (line 174) | pub fn input(&'a self, name: impl Into<String>, bit_width: u32) -> &Inpu...
  function output (line 228) | pub fn output(&'a self, name: impl Into<String>, source: &'a dyn Signal<...
  function reg (line 267) | pub fn reg(&'a self, name: impl Into<String>, bit_width: u32) -> &Regist...
  function mux (line 319) | pub fn mux(
  function mem (line 390) | pub fn mem(
  function module (line 441) | fn module(&'a self, instance_name: impl Into<String>, name: impl Into<St...
  method hash (line 458) | fn hash<H: Hasher>(&self, state: &mut H) {
  method eq (line 464) | fn eq(&self, other: &Self) -> bool {
  type Input (line 473) | pub struct Input<'a> {
  function drive (line 485) | pub fn drive(&'a self, i: &'a dyn Signal<'a>) {
  function internal_signal (line 509) | fn internal_signal(&'a self) -> &'a InternalSignal<'a> {
  function internal_signal (line 515) | fn internal_signal(&'a self) -> &'a InternalSignal<'a> {
  type InputData (line 526) | pub(crate) struct InputData<'a> {
  type Output (line 538) | pub struct Output<'a> {
  type OutputData (line 542) | pub(crate) struct OutputData<'a> {
  function lit_bit_width_lt_min_error (line 560) | fn lit_bit_width_lt_min_error() {
  function lit_bit_width_gt_max_error (line 573) | fn lit_bit_width_gt_max_error() {
  function lit_value_cannot_bit_into_bit_width_error_1 (line 586) | fn lit_value_cannot_bit_into_bit_width_error_1() {
  function lit_value_cannot_bit_into_bit_width_error_2 (line 599) | fn lit_value_cannot_bit_into_bit_width_error_2() {
  function lit_value_cannot_bit_into_bit_width_error_3 (line 612) | fn lit_value_cannot_bit_into_bit_width_error_3() {
  function lit_value_cannot_bit_into_bit_width_error_4 (line 625) | fn lit_value_cannot_bit_into_bit_width_error_4() {
  function input_width_lt_min_error (line 638) | fn input_width_lt_min_error() {
  function input_width_gt_max_error (line 651) | fn input_width_gt_max_error() {
  function output_separate_module_error (line 662) | fn output_separate_module_error() {
  function reg_bit_width_lt_min_error (line 678) | fn reg_bit_width_lt_min_error() {
  function reg_bit_width_gt_max_error (line 691) | fn reg_bit_width_gt_max_error() {
  function mux_cond_separate_module_error (line 702) | fn mux_cond_separate_module_error() {
  function mux_when_true_separate_module_error (line 718) | fn mux_when_true_separate_module_error() {
  function mux_when_false_separate_module_error (line 734) | fn mux_when_false_separate_module_error() {
  function mux_cond_bit_width_error (line 750) | fn mux_cond_bit_width_error() {
  function mux_true_false_bit_width_error (line 766) | fn mux_true_false_bit_width_error() {
  function mem_address_bit_width_lt_min_error (line 782) | fn mem_address_bit_width_lt_min_error() {
  function mem_address_bit_width_gt_max_error (line 795) | fn mem_address_bit_width_gt_max_error() {
  function mem_element_bit_width_lt_min_error (line 808) | fn mem_element_bit_width_lt_min_error() {
  function mem_element_bit_width_gt_max_error (line 821) | fn mem_element_bit_width_gt_max_error() {
  function input_drive_different_module_than_parent_module_error (line 834) | fn input_drive_different_module_than_parent_module_error() {
  function input_drive_already_driven_error (line 853) | fn input_drive_already_driven_error() {
  function input_drive_incompatible_bit_widths_error (line 871) | fn input_drive_incompatible_bit_widths_error() {

FILE: kaze/src/graph/register.rs
  type Register (line 38) | pub struct Register<'a> {
  function default_value (line 71) | pub fn default_value(&'a self, value: impl Into<Constant>) {
  function drive_next (line 108) | pub fn drive_next(&'a self, n: &'a dyn Signal<'a>) {
  type RegisterData (line 123) | pub(crate) struct RegisterData<'a> {
  function internal_signal (line 133) | fn internal_signal(&'a self) -> &'a InternalSignal<'a> {
  function default_value_already_specified_error (line 146) | fn default_value_already_specified_error() {
  function default_value_cannot_bit_into_bit_width_error_1 (line 162) | fn default_value_cannot_bit_into_bit_width_error_1() {
  function default_value_cannot_bit_into_bit_width_error_2 (line 176) | fn default_value_cannot_bit_into_bit_width_error_2() {
  function default_value_cannot_bit_into_bit_width_error_3 (line 190) | fn default_value_cannot_bit_into_bit_width_error_3() {
  function default_value_cannot_bit_into_bit_width_error_4 (line 204) | fn default_value_cannot_bit_into_bit_width_error_4() {
  function drive_next_separate_module_error (line 218) | fn drive_next_separate_module_error() {
  function drive_next_incompatible_bit_width_error (line 235) | fn drive_next_incompatible_bit_width_error() {
  function drive_next_already_driven_error (line 250) | fn drive_next_already_driven_error() {

FILE: kaze/src/graph/signal.rs
  constant MIN_SIGNAL_BIT_WIDTH (line 10) | pub const MIN_SIGNAL_BIT_WIDTH: u32 = 1;
  constant MAX_SIGNAL_BIT_WIDTH (line 14) | pub const MAX_SIGNAL_BIT_WIDTH: u32 = 128;
  type Signal (line 39) | pub trait Signal<'a>: GetInternalSignal<'a> {
    method bit_width (line 78) | fn bit_width(&'a self) -> u32 {
    method bit (line 104) | fn bit(&'a self, index: u32) -> &'a dyn Signal<'a> {
    method bits (line 143) | fn bits(&'a self, range_high: u32, range_low: u32) -> &'a dyn Signal<'...
    method repeat (line 187) | fn repeat(&'a self, count: u32) -> &'a dyn Signal<'a> {
    method concat (line 231) | fn concat(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method eq (line 275) | fn eq(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method ne (line 322) | fn ne(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method lt (line 369) | fn lt(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method le (line 416) | fn le(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method gt (line 463) | fn gt(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method ge (line 510) | fn ge(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method lt_signed (line 557) | fn lt_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method le_signed (line 607) | fn le_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method gt_signed (line 657) | fn gt_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method ge_signed (line 707) | fn ge_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method shr_arithmetic (line 756) | fn shr_arithmetic(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method mul_signed (line 796) | fn mul_signed(&'a self, rhs: &'a dyn Signal<'a>) -> &dyn Signal<'a> {
    method mux (line 841) | fn mux(
  function from (line 1325) | fn from(s: &'a T) -> &'a dyn Signal<'a> {
  type RegNext (line 1330) | pub trait RegNext<'a, S: Into<String>> {
    method reg_next (line 1349) | fn reg_next(self, name: S) -> &'a dyn Signal<'a>;
  type RegNextWithDefault (line 1352) | pub trait RegNextWithDefault<'a, S: Into<String>, C: Into<Constant>> {
    method reg_next_with_default (line 1375) | fn reg_next_with_default(self, name: S, default_value: C) -> &'a dyn S...
  function bit_index_oob_error (line 1386) | fn bit_index_oob_error() {
  function bits_range_low_oob_error (line 1403) | fn bits_range_low_oob_error() {
  function bits_range_high_oob_error (line 1417) | fn bits_range_high_oob_error() {
  function bits_range_low_gt_high_error (line 1431) | fn bits_range_low_gt_high_error() {
  function repeat_count_zero_error (line 1445) | fn repeat_count_zero_error() {
  function repeat_count_oob_error (line 1459) | fn repeat_count_oob_error() {
  function concat_separate_module_error (line 1471) | fn concat_separate_module_error() {
  function concat_oob_error (line 1488) | fn concat_oob_error() {
  function eq_separate_module_error (line 1501) | fn eq_separate_module_error() {
  function eq_incompatible_bit_widths_error (line 1516) | fn eq_incompatible_bit_widths_error() {
  function ne_separate_module_error (line 1529) | fn ne_separate_module_error() {
  function ne_incompatible_bit_widths_error (line 1544) | fn ne_incompatible_bit_widths_error() {
  function lt_separate_module_error (line 1557) | fn lt_separate_module_error() {
  function lt_incompatible_bit_widths_error (line 1572) | fn lt_incompatible_bit_widths_error() {
  function le_separate_module_error (line 1585) | fn le_separate_module_error() {
  function le_incompatible_bit_widths_error (line 1600) | fn le_incompatible_bit_widths_error() {
  function gt_separate_module_error (line 1613) | fn gt_separate_module_error() {
  function gt_incompatible_bit_widths_error (line 1628) | fn gt_incompatible_bit_widths_error() {
  function ge_separate_module_error (line 1641) | fn ge_separate_module_error() {
  function ge_incompatible_bit_widths_error (line 1656) | fn ge_incompatible_bit_widths_error() {
  function lt_signed_separate_module_error (line 1669) | fn lt_signed_separate_module_error() {
  function lt_signed_incompatible_bit_widths_error (line 1684) | fn lt_signed_incompatible_bit_widths_error() {
  function lt_signed_bit_width_1_error (line 1697) | fn lt_signed_bit_width_1_error() {
  function le_signed_separate_module_error (line 1710) | fn le_signed_separate_module_error() {
  function le_signed_incompatible_bit_widths_error (line 1725) | fn le_signed_incompatible_bit_widths_error() {
  function le_signed_bit_width_1_error (line 1738) | fn le_signed_bit_width_1_error() {
  function gt_signed_separate_module_error (line 1751) | fn gt_signed_separate_module_error() {
  function gt_signed_incompatible_bit_widths_error (line 1766) | fn gt_signed_incompatible_bit_widths_error() {
  function gt_signed_bit_width_1_error (line 1779) | fn gt_signed_bit_width_1_error() {
  function ge_signed_separate_module_error (line 1792) | fn ge_signed_separate_module_error() {
  function ge_signed_incompatible_bit_widths_error (line 1807) | fn ge_signed_incompatible_bit_widths_error() {
  function ge_signed_bit_width_1_error (line 1820) | fn ge_signed_bit_width_1_error() {
  function shr_arithmetic_separate_module_error (line 1833) | fn shr_arithmetic_separate_module_error() {
  function mul_signed_separate_module_error (line 1848) | fn mul_signed_separate_module_error() {
  function mul_signed_oob_error (line 1865) | fn mul_signed_oob_error() {
  function mux_cond_separate_module_error (line 1878) | fn mux_cond_separate_module_error() {
  function mux_when_true_separate_module_error (line 1894) | fn mux_when_true_separate_module_error() {
  function mux_when_false_separate_module_error (line 1910) | fn mux_when_false_separate_module_error() {
  function mux_cond_bit_width_error (line 1926) | fn mux_cond_bit_width_error() {
  function mux_true_false_bit_width_error (line 1942) | fn mux_true_false_bit_width_error() {
  function add_separate_module_error (line 1956) | fn add_separate_module_error() {
  function add_incompatible_bit_widths_error (line 1971) | fn add_incompatible_bit_widths_error() {
  function bitand_separate_module_error (line 1984) | fn bitand_separate_module_error() {
  function bitand_incompatible_bit_widths_error (line 1999) | fn bitand_incompatible_bit_widths_error() {
  function bitor_separate_module_error (line 2012) | fn bitor_separate_module_error() {
  function bitor_incompatible_bit_widths_error (line 2027) | fn bitor_incompatible_bit_widths_error() {
  function bitxor_separate_module_error (line 2040) | fn bitxor_separate_module_error() {
  function bitxor_incompatible_bit_widths_error (line 2055) | fn bitxor_incompatible_bit_widths_error() {
  function mul_separate_module_error (line 2068) | fn mul_separate_module_error() {
  function mul_oob_error (line 2085) | fn mul_oob_error() {
  function shl_separate_module_error (line 2098) | fn shl_separate_module_error() {
  function shr_separate_module_error (line 2113) | fn shr_separate_module_error() {
  function sub_separate_module_error (line 2128) | fn sub_separate_module_error() {
  function sub_incompatible_bit_widths_error (line 2143) | fn sub_incompatible_bit_widths_error() {

FILE: kaze/src/graph/sugar.rs
  function if_ (line 27) | pub fn if_<'a, T>(cond: &'a dyn Signal<'a>, when_true: T) -> If<'a, T> {
  type If (line 32) | pub struct If<'a, T> {
  function new (line 38) | fn new(cond: &'a dyn Signal<'a>, when_true: T) -> If<'a, T> {
  function else_if (line 42) | pub fn else_if(self, cond: &'a dyn Signal<'a>, when_true: T) -> ElseIf<'...
  function else_ (line 52) | pub fn else_<F: Into<&'a dyn Signal<'a>>>(self, when_false: F) -> &'a dy...
  type ElseIfParent (line 98) | enum ElseIfParent<'a, T> {
  type ElseIf (line 104) | pub struct ElseIf<'a, T> {
  function else_if (line 111) | pub fn else_if(self, cond: &'a dyn Signal<'a>, when_true: T) -> ElseIf<'...
  function else_ (line 121) | pub fn else_<F: Into<&'a dyn Signal<'a>>>(self, when_false: F) -> &'a dy...

FILE: kaze/src/runtime/tracing.rs
  type TraceValue (line 9) | pub enum TraceValue {
  type TraceValueType (line 21) | pub enum TraceValueType {
    method from_bit_width (line 29) | pub(crate) fn from_bit_width(bit_width: u32) -> TraceValueType {
  type Trace (line 44) | pub trait Trace {
    method push_module (line 47) | fn push_module(&mut self, name: &'static str) -> io::Result<()>;
    method pop_module (line 48) | fn pop_module(&mut self) -> io::Result<()>;
    method add_signal (line 49) | fn add_signal(
    method update_time_stamp (line 56) | fn update_time_stamp(&mut self, time_stamp: u64) -> io::Result<()>;
    method update_signal (line 57) | fn update_signal(&mut self, signal_id: &Self::SignalId, value: TraceVa...

FILE: kaze/src/runtime/tracing/vcd.rs
  type TimeScaleUnit (line 9) | pub enum TimeScaleUnit {
  function from (line 19) | fn from(time_scale_unit: TimeScaleUnit) -> Self {
  type VcdTrace (line 31) | pub struct VcdTrace<W: io::Write> {
  function new (line 40) | pub fn new(w: W, time_scale: u32, time_scale_unit: TimeScaleUnit) -> io:...
  type SignalId (line 56) | type SignalId = usize;
  method push_module (line 58) | fn push_module(&mut self, name: &'static str) -> io::Result<()> {
  method pop_module (line 66) | fn pop_module(&mut self) -> io::Result<()> {
  method add_signal (line 78) | fn add_signal(
  method update_time_stamp (line 96) | fn update_time_stamp(&mut self, time_stamp: u64) -> io::Result<()> {
  method update_signal (line 100) | fn update_signal(&mut self, signal_id: &Self::SignalId, value: TraceValu...
  type VcdTraceSignal (line 131) | struct VcdTraceSignal {

FILE: kaze/src/sim.rs
  type GenerationOptions (line 21) | pub struct GenerationOptions {
  function generate (line 27) | pub fn generate<'a, W: Write>(
  function undriven_instance_input_error (line 749) | fn undriven_instance_input_error() {
  function undriven_register_error1 (line 764) | fn undriven_register_error1() {
  function undriven_register_error2 (line 778) | fn undriven_register_error2() {
  function mem_without_read_ports_error1 (line 793) | fn mem_without_read_ports_error1() {
  function mem_without_read_ports_error2 (line 807) | fn mem_without_read_ports_error2() {
  function mem_without_initial_contents_or_write_port_error1 (line 822) | fn mem_without_initial_contents_or_write_port_error1() {
  function mem_without_initial_contents_or_write_port_error2 (line 837) | fn mem_without_initial_contents_or_write_port_error2() {
  function combinational_loop_error (line 853) | fn combinational_loop_error() {

FILE: kaze/src/sim/compiler.rs
  type Compiler (line 11) | pub(super) struct Compiler<'graph, 'context, 'expr_arena> {
  function new (line 22) | pub fn new(
  function compile_signal (line 39) | pub fn compile_signal(
  function gen_mask (line 564) | fn gen_mask(
  function gen_shift_left (line 591) | fn gen_shift_left(
  function gen_shift_right (line 609) | fn gen_shift_right(
  function gen_cast (line 627) | fn gen_cast(
  function gen_sign_extend_shifts (line 661) | fn gen_sign_extend_shifts(

FILE: kaze/src/sim/ir.rs
  type AssignmentContext (line 8) | pub struct AssignmentContext<'arena> {
  function new (line 15) | pub fn new(arena: &'arena Arena<Expr<'arena>>) -> AssignmentContext<'are...
  function gen_temp (line 23) | pub fn gen_temp(&mut self, expr: &'arena Expr<'arena>) -> &'arena Expr<'...
  function is_empty (line 47) | pub fn is_empty(&self) -> bool {
  function push (line 51) | pub fn push(&mut self, assignment: Assignment<'arena>) {
  function write (line 55) | pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Res...
  type Assignment (line 64) | pub struct Assignment<'arena> {
  function write (line 70) | pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Res...
  type Expr (line 91) | pub enum Expr<'arena> {
  function from_constant (line 134) | pub fn from_constant(
  function write (line 153) | pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Res...
  type Constant (line 281) | pub enum Constant {
  type InfixBinOp (line 289) | pub enum InfixBinOp {
  type Scope (line 305) | pub enum Scope {
  type UnOp (line 311) | pub enum UnOp {
  type ValueType (line 316) | pub enum ValueType {
    method from_bit_width (line 327) | pub fn from_bit_width(bit_width: u32) -> ValueType {
    method to_signed (line 341) | pub fn to_signed(&self) -> ValueType {
    method name (line 350) | pub fn name(&self) -> &'static str {
    method bit_width (line 362) | pub fn bit_width(&self) -> u32 {
    method zero_str (line 371) | pub fn zero_str(&self) -> &'static str {

FILE: kaze/src/state_elements.rs
  type Register (line 6) | pub(super) struct Register<'a> {
  type Mem (line 12) | pub(super) struct Mem<'a> {
  type ReadSignalNames (line 27) | pub struct ReadSignalNames {
  type IncludedPorts (line 36) | pub(super) enum IncludedPorts {
  type StateElements (line 41) | pub(super) struct StateElements<'a> {
  function new (line 47) | pub fn new(
  function visit_module (line 68) | fn visit_module<'a>(
  function visit_signal (line 112) | fn visit_signal<'a>(

FILE: kaze/src/validation.rs
  function validate_module_hierarchy (line 4) | pub fn validate_module_hierarchy<'a>(m: &'a graph::Module<'a>) {
  function detect_undriven_registers_and_inputs (line 10) | fn detect_undriven_registers_and_inputs<'a>(m: &graph::Module<'a>, root:...
  function detect_mem_errors (line 33) | fn detect_mem_errors<'a>(m: &graph::Module<'a>, root: &graph::Module<'a>) {
  function detect_combinational_loops (line 49) | fn detect_combinational_loops<'a>(m: &graph::Module<'a>, root: &graph::M...
  function trace_signal (line 59) | fn trace_signal<'a>(

FILE: kaze/src/verilog.rs
  function generate (line 18) | pub fn generate<'a, W: Write>(m: &'a graph::Module<'a>, w: W) -> Result<...
  function undriven_instance_input_error (line 294) | fn undriven_instance_input_error() {
  function undriven_register_error1 (line 309) | fn undriven_register_error1() {
  function undriven_register_error2 (line 323) | fn undriven_register_error2() {
  function mem_without_read_ports_error1 (line 338) | fn mem_without_read_ports_error1() {
  function mem_without_read_ports_error2 (line 352) | fn mem_without_read_ports_error2() {
  function mem_without_initial_contents_or_write_port_error1 (line 367) | fn mem_without_initial_contents_or_write_port_error1() {
  function mem_without_initial_contents_or_write_port_error2 (line 382) | fn mem_without_initial_contents_or_write_port_error2() {
  function combinational_loop_error (line 398) | fn combinational_loop_error() {

FILE: kaze/src/verilog/compiler.rs
  type Compiler (line 8) | pub(super) struct Compiler<'graph> {
  function new (line 13) | pub fn new() -> Compiler<'graph> {
  function compile_signal (line 19) | pub fn compile_signal(

FILE: kaze/src/verilog/ir.rs
  type NodeDecl (line 6) | pub struct NodeDecl {
    method write (line 13) | pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> R...
  type NetType (line 27) | pub enum NetType {
    method write (line 33) | pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> R...
  type AssignmentContext (line 41) | pub struct AssignmentContext {
    method new (line 47) | pub fn new() -> AssignmentContext {
    method gen_temp (line 54) | pub fn gen_temp(&mut self, expr: Expr, bit_width: u32, name_prefix: St...
    method is_empty (line 71) | pub fn is_empty(&self) -> bool {
    method push (line 75) | pub fn push(&mut self, assignment: Assignment) {
    method write (line 79) | pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> R...
  type Assignment (line 95) | pub struct Assignment {
    method write (line 101) | fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> Resul...
  type Expr (line 114) | pub enum Expr {
    method from_constant (line 155) | pub fn from_constant(value: &graph::Constant, bit_width: u32) -> Expr {
    method write (line 162) | pub fn write<W: Write>(&self, w: &mut code_writer::CodeWriter<W>) -> R...
  type BinOp (line 247) | pub enum BinOp {
  type UnOp (line 266) | pub enum UnOp {

FILE: sim-tests/build.rs
  function main (line 8) | fn main() -> Result<()> {
  function input_masking (line 256) | fn input_masking<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function widest_input (line 264) | fn widest_input<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function add_test_module (line 272) | fn add_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function sub_test_module (line 302) | fn sub_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function mul_test_module (line 332) | fn mul_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function mul_signed_test_module (line 366) | fn mul_signed_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'...
  function shl_test_module (line 400) | fn shl_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function shr_test_module (line 442) | fn shr_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function shr_arithmetic_test_module (line 484) | fn shr_arithmetic_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Modu...
  function bit_and_test_module (line 526) | fn bit_and_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function bit_or_test_module (line 536) | fn bit_or_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function bit_xor_test_module (line 546) | fn bit_xor_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function not_test_module (line 556) | fn not_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function reg_test_module (line 565) | fn reg_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function simple_reg_delay (line 580) | fn simple_reg_delay<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function bit_test_module_0 (line 597) | fn bit_test_module_0<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function bit_test_module_1 (line 606) | fn bit_test_module_1<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function bits_test_module_0 (line 618) | fn bits_test_module_0<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function bits_test_module_1 (line 632) | fn bits_test_module_1<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function repeat_test_module (line 653) | fn repeat_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function concat_test_module (line 671) | fn concat_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function eq_test_module (line 689) | fn eq_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function ne_test_module (line 700) | fn ne_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function lt_test_module (line 711) | fn lt_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function le_test_module (line 722) | fn le_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function gt_test_module (line 733) | fn gt_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function ge_test_module (line 744) | fn ge_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function lt_signed_test_module (line 755) | fn lt_signed_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function le_signed_test_module (line 766) | fn le_signed_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function gt_signed_test_module (line 777) | fn gt_signed_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function ge_signed_test_module (line 788) | fn ge_signed_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function mux_test_module (line 799) | fn mux_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function reg_next_test_module (line 831) | fn reg_next_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function reg_next_with_default_test_module (line 842) | fn reg_next_with_default_test_module<'a>(p: &'a impl ModuleParent<'a>) -...
  function instantiation_test_module_comb (line 856) | fn instantiation_test_module_comb<'a>(p: &'a impl ModuleParent<'a>) -> &...
  function instantiation_test_module_reg (line 895) | fn instantiation_test_module_reg<'a>(p: &'a impl ModuleParent<'a>) -> &M...
  function nested_instantiation_test_module (line 936) | fn nested_instantiation_test_module<'a>(p: &'a impl ModuleParent<'a>) ->...
  function mem_test_module_0 (line 993) | fn mem_test_module_0<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function mem_test_module_1 (line 1011) | fn mem_test_module_1<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function mem_test_module_2 (line 1025) | fn mem_test_module_2<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function trace_test_module_0 (line 1043) | fn trace_test_module_0<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function trace_test_module_1 (line 1055) | fn trace_test_module_1<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function trace_test_module_2 (line 1070) | fn trace_test_module_2<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function trace_test_module_3 (line 1108) | fn trace_test_module_3<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'a> {
  function deep_graph_test_module (line 1126) | fn deep_graph_test_module<'a>(p: &'a impl ModuleParent<'a>) -> &Module<'...

FILE: sim-tests/src/lib.rs
  type CodeWriter (line 19) | struct CodeWriter<'a, 'b> {
  function new (line 25) | fn new(f: &'a mut fmt::Formatter<'b>) -> CodeWriter<'a, 'b> {
  function indent (line 29) | fn indent(&mut self) {
  function unindent (line 33) | fn unindent(&mut self) {
  function append_indent (line 40) | fn append_indent(&mut self) -> fmt::Result {
  function append_newline (line 47) | fn append_newline(&mut self) -> fmt::Result {
  function append (line 52) | fn append(&mut self, s: &str) -> fmt::Result {
  function append_line (line 57) | fn append_line(&mut self, s: &str) -> fmt::Result {
  type Capture (line 66) | struct Capture {
    method fmt (line 71) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    method new (line 113) | fn new() -> Capture {
  type CaptureModule (line 119) | struct CaptureModule {
  type CaptureSignal (line 125) | struct CaptureSignal {
  type CaptureTrace (line 131) | struct CaptureTrace<'a> {
  function new (line 140) | fn new(capture: &'a mut Capture) -> CaptureTrace<'a> {
  type SignalId (line 152) | type SignalId = Rc<CaptureSignal>;
  method push_module (line 154) | fn push_module(&mut self, name: &'static str) -> io::Result<()> {
  method pop_module (line 166) | fn pop_module(&mut self) -> io::Result<()> {
  method add_signal (line 183) | fn add_signal(
  method update_time_stamp (line 202) | fn update_time_stamp(&mut self, time_stamp: u64) -> io::Result<()> {
  method update_signal (line 208) | fn update_signal(
  function input_masking (line 220) | fn input_masking() {
  function widest_input (line 229) | fn widest_input() {
  function add_test_module (line 238) | fn add_test_module() {
  function sub_test_module (line 308) | fn sub_test_module() {
  function mul_test_module (line 378) | fn mul_test_module() {
  function mul_signed_test_module (line 436) | fn mul_signed_test_module() {
  function shl_test_module (line 494) | fn shl_test_module() {
  function shr_test_module (line 649) | fn shr_test_module() {
  function shr_arithmetic_test_module (line 804) | fn shr_arithmetic_test_module() {
  function bit_and_test_module (line 1014) | fn bit_and_test_module() {
  function bit_or_test_module (line 1045) | fn bit_or_test_module() {
  function bit_xor_test_module (line 1076) | fn bit_xor_test_module() {
  function not_test_module (line 1107) | fn not_test_module() {
  function reg_test_module (line 1128) | fn reg_test_module() {
  function simple_reg_delay (line 1162) | fn simple_reg_delay() {
  function bit_test_module_0 (line 1186) | fn bit_test_module_0() {
  function bit_test_module_1 (line 1199) | fn bit_test_module_1() {
  function bits_test_module_0 (line 1211) | fn bits_test_module_0() {
  function bits_test_module_1 (line 1240) | fn bits_test_module_1() {
  function repeat_test_module (line 1260) | fn repeat_test_module() {
  function concat_test_module (line 1289) | fn concat_test_module() {
  function eq_test_module (line 1306) | fn eq_test_module() {
  function ne_test_module (line 1323) | fn ne_test_module() {
  function lt_test_module (line 1340) | fn lt_test_module() {
  function le_test_module (line 1357) | fn le_test_module() {
  function gt_test_module (line 1374) | fn gt_test_module() {
  function ge_test_module (line 1391) | fn ge_test_module() {
  function lt_signed_test_module (line 1408) | fn lt_signed_test_module() {
  function le_signed_test_module (line 1425) | fn le_signed_test_module() {
  function gt_signed_test_module (line 1442) | fn gt_signed_test_module() {
  function ge_signed_test_module (line 1459) | fn ge_signed_test_module() {
  function mux_test_module (line 1476) | fn mux_test_module() {
  function reg_next_test_module (line 1521) | fn reg_next_test_module() {
  function reg_next_with_default_test_module (line 1545) | fn reg_next_with_default_test_module() {
  function instantiation_test_module_comb (line 1570) | fn instantiation_test_module_comb() {
  function instantiation_test_module_reg (line 1589) | fn instantiation_test_module_reg() {
  function nested_instantiation_test_module (line 1613) | fn nested_instantiation_test_module() {
  function mem_test_module_0 (line 1632) | fn mem_test_module_0() {
  function mem_test_module_1 (line 1805) | fn mem_test_module_1() {
  function mem_test_module_2 (line 1864) | fn mem_test_module_2() {
  function trace_test_module_0 (line 2037) | fn trace_test_module_0() -> io::Result<()> {
  function trace_test_module_1 (line 2200) | fn trace_test_module_1() -> io::Result<()> {
  function trace_test_module_2 (line 2346) | fn trace_test_module_2() -> io::Result<()> {
  function trace_test_module_3 (line 2529) | fn trace_test_module_3() -> io::Result<()> {
  function deep_graph_test_module (line 2840) | fn deep_graph_test_module() {
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (434K chars).
[
  {
    "path": ".gitignore",
    "chars": 19,
    "preview": "Cargo.lock\ntarget/\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 5807,
    "preview": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changel"
  },
  {
    "path": "Cargo.toml",
    "chars": 56,
    "preview": "[workspace]\n\nmembers = [\n    \"kaze\",\n    \"sim-tests\",\n]\n"
  },
  {
    "path": "LICENSE-APACHE",
    "chars": 10848,
    "preview": "                              Apache License\n                        Version 2.0, January 2004\n                     http"
  },
  {
    "path": "LICENSE-MIT",
    "chars": 1069,
    "preview": "Copyright (c) 2019-2021 Jake \"ferris\" Taylor\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a co"
  },
  {
    "path": "README.md",
    "chars": 3452,
    "preview": "# kaze [風](https://jisho.org/search/%E9%A2%A8%20%23kanji)\n\nAn [HDL](https://en.wikipedia.org/wiki/Hardware_description_l"
  },
  {
    "path": "kaze/Cargo.toml",
    "chars": 548,
    "preview": "[package]\nname = \"kaze\"\nversion = \"0.1.19\" # Must be kept up-to-date with html_root_url in lib.rs\nauthors = [\"Jake \\\"fer"
  },
  {
    "path": "kaze/src/code_writer.rs",
    "chars": 1002,
    "preview": "use std::io::{Result, Write};\n\npub struct CodeWriter<W: Write> {\n    w: W,\n    indent_level: u32,\n}\n\nimpl<W: Write> Code"
  },
  {
    "path": "kaze/src/graph/constant.rs",
    "chars": 2291,
    "preview": "/// A container for different types of integer constant values.\n///\n/// This type isn't typically used explicitly, as th"
  },
  {
    "path": "kaze/src/graph/context.rs",
    "chars": 3489,
    "preview": "use super::internal_signal::*;\nuse super::mem::*;\nuse super::module::*;\nuse super::register::*;\n\nuse typed_arena::Arena;"
  },
  {
    "path": "kaze/src/graph/internal_signal.rs",
    "chars": 5108,
    "preview": "use super::constant::*;\nuse super::context::*;\nuse super::mem::*;\nuse super::module::*;\nuse super::register::*;\n\nuse std"
  },
  {
    "path": "kaze/src/graph/mem.rs",
    "chars": 15042,
    "preview": "use super::constant::*;\nuse super::context::*;\nuse super::internal_signal::*;\nuse super::module::*;\nuse super::signal::*"
  },
  {
    "path": "kaze/src/graph/module.rs",
    "chars": 27130,
    "preview": "use super::constant::*;\nuse super::context::*;\nuse super::internal_signal::*;\nuse super::mem::*;\nuse super::register::*;"
  },
  {
    "path": "kaze/src/graph/register.rs",
    "chars": 9272,
    "preview": "use super::constant::*;\nuse super::internal_signal::*;\nuse super::module::*;\nuse super::signal::*;\n\nuse std::cell::RefCe"
  },
  {
    "path": "kaze/src/graph/signal.rs",
    "chars": 72547,
    "preview": "use super::constant::*;\nuse super::internal_signal::*;\n\nuse std::ops::{Add, BitAnd, BitOr, BitXor, Mul, Not, Shl, Shr, S"
  },
  {
    "path": "kaze/src/graph/sugar.rs",
    "chars": 5702,
    "preview": "use super::signal::*;\n\n/// **UNSTABLE:** Provides a convenient way to write conditional combinational logic.\n///\n/// # P"
  },
  {
    "path": "kaze/src/graph.rs",
    "chars": 252,
    "preview": "mod constant;\nmod context;\npub(crate) mod internal_signal;\nmod mem;\nmod module;\nmod register;\nmod signal;\nmod sugar;\n\npu"
  },
  {
    "path": "kaze/src/lib.rs",
    "chars": 1566,
    "preview": "//! An [HDL](https://en.wikipedia.org/wiki/Hardware_description_language) embedded in [Rust](https://www.rust-lang.org/)"
  },
  {
    "path": "kaze/src/runtime/tracing/vcd.rs",
    "chars": 3504,
    "preview": "//! [VCD](https://en.wikipedia.org/wiki/Value_change_dump) format tracing implementation.\n\nextern crate vcd;\n\nuse super:"
  },
  {
    "path": "kaze/src/runtime/tracing.rs",
    "chars": 1534,
    "preview": "//! Rust simulator runtime dependencies for tracing.\n\npub mod vcd;\n\nuse std::io;\n\n// TODO: Do we want to re-use graph::C"
  },
  {
    "path": "kaze/src/runtime.rs",
    "chars": 120,
    "preview": "//! Rust simulator runtime dependencies. These are only required for simulators with tracing enabled.\n\npub mod tracing;\n"
  },
  {
    "path": "kaze/src/sim/compiler.rs",
    "chars": 32993,
    "preview": "use super::ir::*;\n\nuse crate::graph::internal_signal;\nuse crate::state_elements::*;\n\nuse typed_arena::Arena;\n\nuse std::c"
  },
  {
    "path": "kaze/src/sim/ir.rs",
    "chars": 11783,
    "preview": "use crate::code_writer;\nuse crate::graph;\n\nuse typed_arena::Arena;\n\nuse std::io::{Result, Write};\n\npub struct Assignment"
  },
  {
    "path": "kaze/src/sim.rs",
    "chars": 29339,
    "preview": "//! Rust simulator code generation.\n\nmod compiler;\nmod ir;\n\nuse compiler::*;\nuse ir::*;\n\nuse typed_arena::Arena;\n\nuse cr"
  },
  {
    "path": "kaze/src/state_elements.rs",
    "chars": 10038,
    "preview": "use crate::graph;\nuse crate::graph::internal_signal;\n\nuse std::collections::HashMap;\n\npub(super) struct Register<'a> {\n "
  },
  {
    "path": "kaze/src/validation.rs",
    "chars": 6169,
    "preview": "use crate::graph;\nuse crate::graph::internal_signal;\n\npub fn validate_module_hierarchy<'a>(m: &'a graph::Module<'a>) {\n "
  },
  {
    "path": "kaze/src/verilog/compiler.rs",
    "chars": 19970,
    "preview": "use super::ir::*;\n\nuse crate::internal_signal;\nuse crate::state_elements::*;\n\nuse std::collections::HashMap;\n\npub(super)"
  },
  {
    "path": "kaze/src/verilog/ir.rs",
    "chars": 6493,
    "preview": "use crate::code_writer;\nuse crate::graph;\n\nuse std::io::{Result, Write};\n\npub struct NodeDecl {\n    pub net_type: NetTyp"
  },
  {
    "path": "kaze/src/verilog.rs",
    "chars": 13243,
    "preview": "//! Verilog code generation.\n\nmod compiler;\nmod ir;\n\nuse compiler::*;\nuse ir::*;\n\nuse crate::code_writer;\nuse crate::gra"
  },
  {
    "path": "sim-tests/Cargo.toml",
    "chars": 364,
    "preview": "[package]\nname = \"sim-tests\"\nversion = \"0.1.0\"\nauthors = [\"Jake \\\"ferris\\\" Taylor <yupferris@gmail.com>\"]\nedition = \"201"
  },
  {
    "path": "sim-tests/build.rs",
    "chars": 30152,
    "preview": "use kaze::*;\n\nuse std::env;\nuse std::fs::File;\nuse std::io::Result;\nuse std::path::Path;\n\nfn main() -> Result<()> {\n    "
  },
  {
    "path": "sim-tests/src/lib.rs",
    "chars": 85258,
    "preview": "#[cfg(test)]\nmod tests {\n    extern crate kaze;\n\n    mod modules {\n        include!(concat!(env!(\"OUT_DIR\"), \"/modules.r"
  }
]

About this extraction

This page contains the full source code of the yupferris/kaze GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (406.4 KB), approximately 101.2k tokens, and a symbol index with 410 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!