2 releases
Uses new Rust 2024
new 0.1.1 | Apr 28, 2025 |
---|---|
0.1.0 | Apr 28, 2025 |
#5 in #circuit
74 downloads per month
53KB
750 lines
libttl - TTL Logic Simulation Library
libttl
is a Rust library designed for simulating basic TTL (Transistor-Transistor Logic) chips and circuits. It provides foundational components like logic levels and gates, implementations of several common 74xx series chips, and a circuit simulator to connect and run them.
This library is primarily intended for educational purposes and hobbyist digital logic simulation.
Features
LogicLevel
: RepresentsHigh
andLow
states with boolean conversions and basic logic operations.Gate
Trait: A common interface for logic gates, supporting potential statefulness (though basic gates are stateless).- Implementations:
NotGate
,AndGate
,OrGate
,NandGate
.
- Implementations:
Chip
Trait: An interface for simulating TTL chips, managing pin states, types, and internal logic updates.- Implementations:
Chip7400
(Quad NAND),Chip7404
(Hex Inverter),Chip7408
(Quad AND),Chip7432
(Quad OR).
- Implementations:
Circuit
Simulator: Allows you to:- Add multiple
Chip
instances to a circuit. - Define connections (
wires
) between chip pins. - Set external input levels.
- Simulate circuit behavior step-by-step (
tick()
) or run for multiple steps (run()
). - Probe the logic levels of output pins.
- Add multiple
- Basic Clocking: The
Circuit::tick()
method provides a discrete time step simulation, propagating signals through connected components. - Comprehensive Tests: Includes unit tests for gates and integration tests for each implemented chip.
Library Structure
The library is organized into several modules:
logic_level
: Defines theLogicLevel
enum and related helpers.gates
: Defines theGate
trait and basic gate implementations.chips
: Defines theChip
trait, common pin types (PinType
), and specific chip implementations (e.g.,chips::Chip7400
).circuit
: Defines theCircuit
struct for building and simulating interconnected chips.
Installation
You can add libttl
as a dependency in your Cargo.toml:
[dependencies]
libttl = "0.1.0"
Basic Usage
Using a Single Chip
use libttl::chips::{Chip, Chip7404}; // Example: Use the 7404 Hex Inverter
use libttl::logic_level::LogicLevel::{High, Low};
fn main() {
// Create a new chip instance
let mut inverter_chip = Chip7404::new();
// Set an input pin (Pin 1 on 7404 is Input 1A)
inverter_chip.set_input(1, High);
// Update the chip's internal state based on inputs
inverter_chip.update();
// Get the corresponding output pin state (Pin 2 on 7404 is Output 1Y)
let output_level = inverter_chip.get_output(2);
println!("Input Pin 1: High");
println!("Output Pin 2: {:?}", output_level); // Expected: Low
// Change the input
inverter_chip.set_input(1, Low);
inverter_chip.update();
let output_level = inverter_chip.get_output(2);
println!("Input Pin 1: Low");
println!("Output Pin 2: {:?}", output_level); // Expected: High
}
Using a Circuit
use libttl::circuit::Circuit;
use libttl::chips::{Chip7404, Chip7408};
use libttl::logic_level::LogicLevel::{High, Low};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut circuit = Circuit::new();
// Add chips to the circuit
let inv_chip_idx = circuit.add_chip(Box::new(Chip7404::new())); // Chip 0
let and_chip_idx = circuit.add_chip(Box::new(Chip7408::new())); // Chip 1
// Wire inverter output (Pin 2) to AND gate input A (Pin 1)
circuit.add_wire(inv_chip_idx, 2, and_chip_idx, 1)?;
// Set external inputs
// Set inverter input (Pin 1 on chip 0)
circuit.set_external_input(inv_chip_idx, 1, High)?;
// Set AND gate input B (Pin 2 on chip 1)
circuit.set_external_input(and_chip_idx, 2, High)?;
// Simulate one clock tick for signals to propagate
println!("Before tick:");
// Note: Output of AND gate might be Low initially before propagation
println!(" Inverter Out (Pin 2): {:?}", circuit.get_output_level(inv_chip_idx, 2)); // Expect Low after update
println!(" AND Out (Pin 3): {:?}", circuit.get_output_level(and_chip_idx, 3)); // Expect Low
circuit.tick(); // Evaluate connections, commit inputs, update chips
println!("After tick:");
let inv_out = circuit.get_output_level(inv_chip_idx, 2)?;
let and_out = circuit.get_output_level(and_chip_idx, 3)?;
// Inverter input was High -> Inverter output (Pin 2) is Low
// AND inputs are now Low (from inverter) and High (external) -> AND output (Pin 3) is Low
println!(" Inverter Out (Pin 2): {:?}", inv_out); // Expected: Low
println!(" AND Out (Pin 3): {:?}", and_out); // Expected: Low
assert_eq!(inv_out, Low);
assert_eq!(and_out, Low);
Ok(())
}
Running Tests
The library has unit tests for gates and chips located in the tests/ directory. To run all tests:
cargo test
Running Examples
The library includes examples in the examples
directory. Run them with:
sr_latch
: Implements a standard active-low SR NAND latch using a 7400 chip.multi_gate_unit
: Implements a simple 2-input logic unit with selectable AND/OR functions, using one of each implemented chip (7400, 7404, 7408, 7432).
To run an example, run:
# Run the SR Latch example
cargo run --example sr_latch
# Run the Multi-Gate Logic Unit example
cargo run --example multi_gate_unit
Contributing
Contributions are welcome! Whether it's adding more chips, implementing more complex gates, improving the circuit simulator, adding documentation, or fixing bugs, your help is appreciated.
Possible Areas for Contribution:
- Implement more 74xx series chips (e.g., 7474 D-FlipFlop, 7486 XOR, multiplexers, decoders).
- Implement more complex/stateful gates (e.g., Flip-Flops as basic Gate implementations).
- Add support for tristate logic or floating pins (LogicLevel::HighZ).
- Model propagation delays more accurately in the Circuit simulator.
- Improve error handling and reporting.
- Add more examples and documentation.
Contribution Workflow:
- Fork the repository.
- Create a new branch for your changes.
- Make your changes. Please follow Rust style guidelines (https://rust-lang.github.io/rustfmt/).
- Add tests for your changes and ensure they pass.
- Format your code:
cargo fmt
. - Commit your changes with a clear commit message:
git commit -m "Your commit message"
- Push your changes to your forked repository.
- Create a pull request to merge your changes into the main repository.
If you plan to make significant changes, it's a good idea to open an issue first to discuss the approach.
License
This project is licensed under the MIT License.
Copyright (c) 2025 Drew Walton
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.