libttl 0.1.1

A library for simulating TTL logic chips
Documentation
//! Implementation of the 7400 Quad 2-input NAND gate chip.

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

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

const PIN_COUNT_7400: usize = 14;

#[derive(Debug, Clone)]
pub struct Chip7400 {
    pin_state: Vec<LogicLevel>,
    gates: [NandGate; 4],
}

impl Chip7400 {
    pub fn new() -> Self {
        let mut pin_state = vec![LogicLevel::Low; PIN_COUNT_7400 + 1];
        pin_state[14] = LogicLevel::High; // Vcc
        pin_state[7] = LogicLevel::Low;  // Gnd
        // Initialize NAND outputs to High by default
        pin_state[3] = LogicLevel::High;
        pin_state[6] = LogicLevel::High;
        pin_state[8] = LogicLevel::High;
        pin_state[11] = LogicLevel::High;


        Chip7400 {
            pin_state,
            gates: [NandGate::new(), NandGate::new(), NandGate::new(), NandGate::new()],
        }
    }
}

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

impl Chip for Chip7400 {
     fn name(&self) -> &'static str { "7400" }
    fn pin_count(&self) -> usize { PIN_COUNT_7400 }

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

     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 7400", 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 7400", pin);
         match pin {
             3 => self.gates[0].get_output(0),
             6 => self.gates[1].get_output(0),
             8 => self.gates[2].get_output(0),
            11 => self.gates[3].get_output(0),
            _ => unreachable!(),
        }
    }

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

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

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

        // Gate 4 (Pins 12, 13 -> 11)
        self.gates[3].update(&[self.pin_state[12], self.pin_state[13]]);
        self.pin_state[11] = self.gates[3].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())
    }
}