libttl 0.1.1

A library for simulating TTL logic chips
Documentation
//! Implementation of the 7404 Hex Inverter chip.

use crate::chips::common::{validate_pin, Chip, PinType};
use crate::gates::{Gate, NotGate};
use crate::logic_level::LogicLevel;

// 7404 Pinout (Standard 14-pin DIP):
//        .--\/--.
// --> 1A |1     14| Vcc
// <-- 1Y |2     13| 6A -->
// --> 2A |3     12| 6Y <--
// <-- 2Y |4     11| 5A -->
// --> 3A |5     10| 5Y <--
// <-- 3Y |6      9| 4A -->
//    GND |7      8| 4Y <--
//        `------'

const PIN_COUNT_7404: usize = 14;

#[derive(Debug, Clone)]
pub struct Chip7404 {
    /// Stores the current logic level state for each pin (1-based index).
    /// Index 0 is unused.
    pin_state: Vec<LogicLevel>,
    /// Internal gates.
    gates: [NotGate; 6],
}

impl Chip7404 {
    pub fn new() -> Self {
        // Initialize pins: VCC=High, GND=Low, others=Low
        let mut pin_state = vec![LogicLevel::Low; PIN_COUNT_7404 + 1];
        pin_state[14] = LogicLevel::High; // Vcc
        pin_state[7] = LogicLevel::Low;  // Gnd

        Chip7404 {
            pin_state,
            gates: [
                NotGate::new(), NotGate::new(), NotGate::new(),
                NotGate::new(), NotGate::new(), NotGate::new(),
            ],
        }
    }
}

impl Default for Chip7404 {
    fn default() -> Self {
        Self::new()
    }
}


impl Chip for Chip7404 {
    fn name(&self) -> &'static str { "7404" }
    fn pin_count(&self) -> usize { PIN_COUNT_7404 }

    fn get_pin_type(&self, pin: usize) -> PinType {
        validate_pin(pin, self.pin_count());
        match pin {
            1 | 3 | 5 | 9 | 11 | 13 => PinType::Input,
            2 | 4 | 6 | 8 | 10 | 12 => PinType::Output,
            14 => PinType::Vcc,
            7 => PinType::Gnd,
            _ => unreachable!("Invalid pin {} for 7404 checked by validate_pin", pin), // Should not happen
        }
    }

    fn set_input(&mut self, pin: usize, level: LogicLevel) {
        validate_pin(pin, self.pin_count());
        assert_eq!(self.get_pin_type(pin), PinType::Input, "Pin {} is not an input pin on 7404", pin);
        self.pin_state[pin] = level;
    }

    fn get_output(&self, pin: usize) -> LogicLevel {
        validate_pin(pin, self.pin_count());
        assert_eq!(self.get_pin_type(pin), PinType::Output, "Pin {} is not an output pin on 7404", pin);
        // Read the *calculated* state, not just the potentially stale value in pin_state
        match pin {
             2 => self.gates[0].get_output(0),
             4 => self.gates[1].get_output(0),
             6 => self.gates[2].get_output(0),
             8 => self.gates[3].get_output(0),
            10 => self.gates[4].get_output(0),
            12 => self.gates[5].get_output(0),
            _ => unreachable!(),
        }
    }

    fn update(&mut self) {
        // Gate 1 (Pins 1 -> 2)
        self.gates[0].update(&[self.pin_state[1]]);
        self.pin_state[2] = self.gates[0].get_output(0);

        // Gate 2 (Pins 3 -> 4)
        self.gates[1].update(&[self.pin_state[3]]);
        self.pin_state[4] = self.gates[1].get_output(0);

        // Gate 3 (Pins 5 -> 6)
        self.gates[2].update(&[self.pin_state[5]]);
        self.pin_state[6] = self.gates[2].get_output(0);

        // Gate 4 (Pins 9 -> 8)
        self.gates[3].update(&[self.pin_state[9]]);
        self.pin_state[8] = self.gates[3].get_output(0);

        // Gate 5 (Pins 11 -> 10)
        self.gates[4].update(&[self.pin_state[11]]);
        self.pin_state[10] = self.gates[4].get_output(0);

        // Gate 6 (Pins 13 -> 12)
        self.gates[5].update(&[self.pin_state[13]]);
        self.pin_state[12] = self.gates[5].get_output(0);

        // Ensure Vcc/Gnd remain constant
        self.pin_state[14] = LogicLevel::High;
        self.pin_state[7] = LogicLevel::Low;
    }

    fn box_clone(&self) -> Box<dyn Chip> {
        Box::new(self.clone())
    }
}