Category: Logic

  • DINO CPU Project – Memory Module Implementation

    DINO CPU Project – Memory Module Implementation

    The Data Storage and Retrieval System

    With the Microcode Decoder operational and generating control words, the next critical subsystem was the Memory Module. This module represents the CPU’s primary storage architecture — both the Program ROM containing instructions and the SRAM providing working memory. The Memory Module bridges the address bus to the data bus, orchestrating read and write operations under control of the microcode signals.

    The implementation demanded meticulous attention to bit ordering, timing constraints, and bus arbitration. As with my other previous builds, this module required multiple schematic revisions to achieve deterministic operation.

    Architectural Overview

    The Memory Module integrates:

    • AT28C256 EEPROM: 32KB Program ROM containing instruction sequences
    • MCM60256 SRAM: 32KB RAM for data storage and manipulation
    • 74LS245 Bus Transceivers: Bidirectional buffers preventing bus contention
    • 74LS121 Monostable Multivibrator: Precision pulse generator for SRAM write timing
    • 16-bit Address Bus: Shared addressing for both ROM and RAM
    • 8-bit Data Bus: Common data pathway with LED monitoring

    Bus Architecture and Arbitration

    The original design specified 74LS244 unidirectional buffers for ROM output. However, the 74LS245 bidirectional transceiver proved superior even for unidirectional operation, providing consistent pinout and better drive characteristics.

    Critical Discovery: I/O7 on both RAM and ROM chips represented the LSB, not the MSB as initially assumed. This revelation required rewiring the entire data bus interface to maintain consistent bit ordering across all modules. The discovery emerged during test rig construction when binary patterns didn’t match expected values.

    Bus Control Strategy:

    • ROM ‘245: DIR tied for output-only operation, OE controlled by ROM_OUT signal
    • RAM ‘245: DIR controlled by RAM_LOAD/RAM_OUT for bidirectional operation
    • Only one transceiver enabled at any time, preventing bus contention

    The SRAM Write Timing Challenge

    Initial attempts to write SRAM using clock phase levels failed consistently. Investigation revealed that the MCM60256 SRAM requires an edge transition on its WE (Write Enable) pin to latch data, not a sustained level.

    Solution: Precision Pulse Generation

    The 74LS121 monostable multivibrator generates a 600ns active-low pulse:

    • Triggered simultaneously with other control signals
    • Provides setup time for data bus stabilization
    • Creates clean falling edge for SRAM write operation
    • Returns high before next clock phase

    RC Timing Calculation

    The 74LS121 pulse width calculation:

    t_pulse = 0.7 × R × C
    600ns = 0.7 × 10kΩ × C
    C = 86pF (100pF selected for margin)
    

    Implementation Note: Both A1 and B inputs required pull-up to VCC for reliable triggering. Initial attempts to use PULSE_REQ directly on the B input created indeterminate behavior.

    Control Signal Architecture

    The Memory Module responds to four control bits from the Microcode Decoder:

    SignalFunctionSource
    ROM_OUTEnable ROM data onto busBank 2, Code 001
    RAM_OUTEnable RAM data onto busBank 2, Code 010
    RAM_LOADWrite bus data to RAMBank 2, Code 011
    PULSE_REQTrigger 121 for write pulseBit 12

    Test Infrastructure Development

    Testing required sophisticated input and output monitoring:

    Input Test Rig

    • 2 × 8-position DIP switches for manual address entry
    • Beckman 3.3kΩ resistor arrays for switch pull-down
    • Direct connection to 16-bit address bus

    Output Monitoring

    • 8 LEDs displaying current data bus state
    • 220Ω current-limiting resistors
    • Visual confirmation of read/write operations

    Test Methodology and Validation

    Dual Test Program Architecture

    Testing the Memory Module required two distinct C programs to validate both ROM and RAM operations independently:

    1. Program ROM Test: Verification of EEPROM read operations
    2. SRAM Test Controller: Coordinated write/read validation with proper control signal timing

    Program ROM Test Development

    The first C program generated test patterns for the AT28C256 EEPROM:

    // Key test addresses and values
    eeprom[0x0000] = 0xAA;  // Alternating bit pattern
    eeprom[0x0001] = 0x55;  // Inverse pattern
    eeprom[0x1234] = 0x12;  // Address-based value
    eeprom[0xABCD] = 0xCD;  // High address test
    

    Test ROM Mini-Microcode Controller

    The critical innovation was developing a dedicated Test ROM that acted as a miniature microcode controller specifically for SRAM testing. This second C program generated control word sequences that could:

    • Write data patterns to the bus
    • Assert RAM_LOAD simultaneously with PULSE_REQ
    • Coordinate RAM_OUT for read verification
    • Maintain proper control signal timing relationships

    This Test ROM approach better reflected actual system integration where the Microcode Decoder would generate all control signals simultaneously, rather than manual switch manipulation that could introduce timing skew.

    Systematic Test Sequence

    1. ROM_OUT Validation
      • Set DIP switches to test address
      • Assert ROM_OUT via Test ROM control pattern
      • Verify LED pattern matches burned EEPROM data
      • Confirmed: ROM data successfully appears on bus
    2. PULSE_REQ Verification
      • Test ROM generates PULSE_REQ signal
      • Monitor 74LS121 output with oscilloscope
      • Confirm 600ns pulse width with clean edges
      • Confirmed: Pulse generation operates within specifications
    3. RAM_LOAD Operation (via Test ROM)
      • Test ROM places data pattern on bus
      • Simultaneously asserts RAM_LOAD and PULSE_REQ
      • All control bits loaded in parallel, mimicking actual microcode operation
      • Confirmed: Data latched into SRAM as expected
    4. RAM_OUT Verification
      • Test ROM switches to read mode
      • Asserts RAM_OUT for previously written address
      • Compare bus output to written value
      • Confirmed: Complete write-read cycle functional

    The mini-microcode Test ROM validated that simultaneous control signal assertion worked correctly — a critical requirement for integration with the actual Microcode Decoder module.

    Debugging Discoveries

    Address Confusion Resolution

    Initial testing showed data corruption — writing to one address but reading incorrect values from another. Root cause: attempting to share the 16-bit address generator between test ROM reads and SRAM operations.

    Solution: Separate address generation for each test phase. This “classic case of trying to move too fast” reinforced the importance of methodical, isolated testing.

    Trigger Logic Refinement

    Original NOR gate configuration for 74LS121 triggering proved unreliable. Multiple schematic revisions led to a clean NAND gate implementation that provided deterministic pulse generation.

    Schematic Evolution

    The Memory Module underwent three major schematic revisions:

    1. Initial design with 74LS244 buffers and level-triggered writes
    2. Migration to 74LS245 transceivers with pulse generator addition
    3. Final refinement of trigger logic and pull-up configurations

    Each revision reflected lessons learned during hardware testing, demonstrating the iterative nature of discrete logic design.

    Engineering Insights

    The Memory Module implementation reinforced several critical principles:

    • Bit Ordering Discipline: Consistent LSB/MSB conventions across all modules prevents cascading debug sessions
    • Edge vs. Level Triggering: Understanding component timing requirements before design prevents fundamental architectural errors
    • Isolated Testing: Attempting to share test infrastructure between different operations creates confusion and masks real issues
    • RC Circuit Fundamentals: The 0.7 factor in 74LS121 timing calculations represents practical engineering constants that must be respected

    Milestone Confirmation

    The Memory Module is fully operational, providing:

    • Reliable ROM instruction fetches
    • Deterministic SRAM read/write cycles
    • Clean bus arbitration without contention
    • Validated timing margins for all operations

    Next Phase: Memory Data Register

    With the Memory Module complete, the next implementation is the Memory Data Register (MDR) — the critical buffer between memory operations and the CPU’s internal registers. The MDR will provide the temporary storage necessary for complex addressing modes and multi-cycle operations.

    The systematic progression continues: each module building upon validated foundations, methodically constructing a complete discrete logic computer from fundamental components.

  • DINO CPU Project – Microcode Decoder Module Implementation

    DINO CPU Project – Microcode Decoder Module Implementation

    The Control Word Generation Module

    Following the completion of the Program Counter module, the next critical milestone in the DINO CPU build was implementing the Microcode Decoder Module. This subsystem is the decoding bridge between the Program Counter, Instruction Register, and datapath — transforming a simple count and timing phases into precise sequences of control signals that orchestrate the CPU’s fetch–decode–execute cycle.

    This marks a shift in the project’s pace: we are now working with deliberate, methodical engineering discipline. No longer in discovery mode, each module is designed on paper, validated logically, then wired and tested against clearly defined criteria before being declared operational.


    Architectural Role

    The Microcode Decoder accepts:

    • Timer Phase from the ring counter
    • Instruction Opcode from the Instruction Register

    These form a 16-bit address into a parallel EEPROM pair:

    • ROM #1: upper byte
    • ROM #2: lower byte

    Example: address 0xBEEF would store 0xBE in ROM #1 and 0xEF in ROM #2. The output directly drives the control lines of the CPU via decoder banks, enabling deterministic hardware sequencing.


    Hardware Selection

    • ROMs: 2 × AT28C64 8-KB EEPROMs, wired in parallel for 16-bit output
    • Decoders: 4 × 74LS138N 3-to-8 demultiplexers to split the 16 control word bits into functional banks, with 4 additional lines reserved for signals that are not mutually exclusive with other control bits.
    • Pulse Generation: 74LS121 monostable multivibrators for intra-phase latching

    ISA Revision and Bit-Ordering Correction

    Early in design, the instruction set was built with the first bit as MSB, but the hardware required it as LSB. Correcting this forced schematic revisions, but clarified the logical flow from opcode to control word.

    Current Instruction Set:

    LDAI, LDBI, STA, STB, NOP, LDA, ADD, MOV, OUT, HLT

    These instructions form the minimum set needed to verify memory transfers, register operations, arithmetic, and output control.


    Control Word Matrix

    The Microcode Decoder produces a 16-bit control word, organized into functional groups:

    Bit(s)Function / Decoder BankCodes & Meanings
    15HALTStart the next phase early
    14MAR_PC_MUXUse MAR or PC as address source for IR
    13PC_UPIncrement Program Counter
    12PULSE_REQ (new)Intra-phase pulse trigger
    11:9Bank 4: ALU Ops000: ALU Disabled
    001: Pass Accumulator
    010: ADD
    011: SUB
    100: AND
    101: OR
    110: XOR
    111: IR_LOAD
    8:6Bank 3: Program Counter Control000: NOP
    001: PC_CLEAR
    010: PC_PRESET
    011: unused
    100: MDR_OUT
    101: SYS_HALT
    110: OUT_REG_LOAD
    111: unused
    5:3Bank 2: Memory Ops000: NOP
    001: ROM_OUT
    010: RAM_OUT
    011: RAM_LOAD
    100: MAR_LO_LOAD
    101: MAR_HI_LOAD
    110: MAR_LOAD
    111: OUT_REG_OUT
    2:0Bank 1: Register Ops000: NOP
    001: REG_A_LOAD
    010: REG_B_LOAD
    011: REG_C_LOAD
    100: REG_A_OUT
    101: REG_B_OUT
    110: REG_C_OUT
    111: MDR_LOAD

    The PULSE_REQ Discovery

    While defining the control word matrix, it became clear that certain latch operations could not reliably complete within a full T-phase. Halting and latching data simultaneously left uncertainty about whether the latch would capture stable data.

    Solution: Introduce an intra-phase pulse (PULSE_REQ) generated by a 74LS121 to trigger latches early enough for guaranteed stability — essential for RAM writes and 74LS373 register loads.


    Boot Sequence Strategy

    • Microcode Addresses 0x0000–0x000F: Reserved for boot sequence
    • Reset mode forces opcode 0x00 into the IR via a 74LS244 buffering hardwired zeros
    • JK flip-flop (74LS73) keeps the opcode at 0x00 until reset mode is released
    • At 0x0000: Microcode resets the PC
    • At 0x000F: PC is incremented
    • IR loads new opcodes only after reset mode ends

    Schematic Development

    The Microcode Decoder and the next modules (MDR, IR, Memory, Registers) have been fully drafted in KiCAD to ensure logical consistency before wiring.


    Test Strategy

    Testing verified correct EEPROM byte pairing for given addresses. DIP switches simulated opcode + timer phase. A multimeter was used to measure each ROM output pin, as the static conditions made it easier than a logic analyzer. Measurements were recorded in the engineering journal and compared to expected binary/hex values.

    Test steps:

    1. Set DIP switches for desired address
    2. Measure each ROM output with multimeter
    3. Record voltage levels, convert to binary/hex
    4. Compare with EEPROM binary file contents
    5. Repeat for all patterns
    AddressROM #1 (High Byte)ROM #2 (Low Byte)
    0x00000xDE0xAD
    0x00010xBE0xEF
    0x0DED0xBE0xEF
    0x0FED0xFE0xED

    Two C programs supported test and verification:

    test.c

    
    /**
     * test.c - Parallel EEPROM test data generator for DINO
     *
     * This program generates two binary files (eeprom1.bin and eeprom2.bin)
     * for burning into two parallel EEPROMs used in the DINO hardware project.
     *
     * Each file is 4096 bytes (0x1000) and specific values are written at key addresses:
     *   - eeprom1.bin: 0xDE at 0x0000, 0xBE at 0x0001, 0xBE at 0x0DED, 0xFE at 0x0FED
     *   - eeprom2.bin: 0xAD at 0x0000, 0xEF at 0x0001, 0xEF at 0x0DED, 0xED at 0x0FED
     *
    #
    # Usage:
    #   To compile:
    #     gcc test.c -o test
    #
    #   To generate the EEPROM files:
    #     ./test
    #
    #   To check the contents of each bin file:
    #     hexdump -C eeprom1.bin
    #     hexdump -C eeprom2.bin
    #
    #   How to read the output:
    #     - The address at the start of each line (e.g., 00000fe0) is the starting offset for that line.
    #     - Each line shows 16 bytes, so the first byte is at the line's address, the second at address+1, etc.
    #     - To find a specific address (e.g., 0x0FED), calculate its position: 0x0FE0 + 13 = 0x0FED (13th byte in the line).
    #     - Count bytes from left to right, starting at 0 for each line.
    #     - Example: If you see 'fe' as the 13th byte on the line starting with 00000fe0, that's the value at 0x0FED.
    #
     * All other bytes are zero-filled. This is for hardware and microcode testing.
     */
    #include <stdio.h>
    #include <stdint.h>
    
    int main(void) {
        FILE *f1 = fopen("eeprom1.bin", "wb");
        FILE *f2 = fopen("eeprom2.bin", "wb");
        if (!f1 || !f2) {
            perror("Failed to open one of the files");
            if (f1) fclose(f1);
            if (f2) fclose(f2);
            return 1;
        }
        uint8_t eeprom1[0x2000] = {0};
        uint8_t eeprom2[0x2000] = {0};
    
        // Fill both EEPROMs with zeros
        for (int i = 0; i < sizeof(eeprom1); i++) {
            eeprom1[i] = 0x00;
            eeprom2[i] = 0x00;
        }
    
        // Write 0xDE at 0x0000 in eeprom1
        eeprom1[0x0000] = 0xDE;
        // Write 0xAD at 0x0000 in eeprom2
        eeprom2[0x0000] = 0xAD;
    
        // Write 0xBE at 0x0001 in eeprom1
        eeprom1[0x0001] = 0xBE;
        // Write 0xEF at 0x0001 in eeprom2
        eeprom2[0x0001] = 0xEF;
    
        // Write 0xBA at 0x0002 in eeprom1
        eeprom1[0x0002] = 0xBA;
        // Write 0xBE at 0x0002 in eeprom2
        eeprom2[0x0002] = 0xBE;
    
        // Write 0xBE at 0x0DED in eeprom1
        eeprom1[0x0DED] = 0xBE;
    
        // Write 0xEF at 0x0DED in eeprom2
        eeprom2[0x0DED] = 0xEF;
    
        // Write 0xCA at 0x0003 in eeprom1
        eeprom1[0x0003] = 0xCA;
        // Write 0xFE at 0x0003 in eeprom2
        eeprom2[0x0003] = 0xFE;
    
        // Write 0xFE at 0x0FED in eeprom1
        eeprom1[0x0FED] = 0xFE;
        // Write 0xED at 0x0FED in eeprom2
        eeprom2[0x0FED] = 0xED;
    
        fwrite(eeprom1, sizeof(uint8_t), sizeof(eeprom1), f1);
        fwrite(eeprom2, sizeof(uint8_t), sizeof(eeprom2), f2);
        fclose(f1);
        fclose(f2);
        return 0;
    }

    verify.c

    /**
     * verify.c - Verifies specific addresses in eeprom1.bin and eeprom2.bin
     *
     * This program reads eeprom1.bin and eeprom2.bin, then prints the values at key addresses:
     *   - 0x0000, 0x0001, 0x0002, 0x0003, 0x0DED, 0x0FED
     *
     * Output format:
     *   EEPROM1[0xADDR] = 0xXX
     *   EEPROM2[0xADDR] = 0xXX
     *
     * Usage:
     *   gcc verify.c -o verify
     *   ./verify
     */
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    
    #define EEPROM_SIZE 0x2000
    
    int main(void) {
        const char *fname1 = "eeprom1.bin";
        const char *fname2 = "eeprom2.bin";
        FILE *f1 = fopen(fname1, "rb");
        FILE *f2 = fopen(fname2, "rb");
        if (!f1 || !f2) {
            perror("Failed to open one of the EEPROM files");
            if (f1) fclose(f1);
            if (f2) fclose(f2);
            return 1;
        }
        uint8_t eeprom1[EEPROM_SIZE];
        uint8_t eeprom2[EEPROM_SIZE];
        if (fread(eeprom1, 1, EEPROM_SIZE, f1) != EEPROM_SIZE) {
            fprintf(stderr, "Error reading %s\n", fname1);
            fclose(f1); fclose(f2);
            return 2;
        }
        if (fread(eeprom2, 1, EEPROM_SIZE, f2) != EEPROM_SIZE) {
            fprintf(stderr, "Error reading %s\n", fname2);
            fclose(f1); fclose(f2);
            return 3;
        }
        fclose(f1);
        fclose(f2);
    
        uint16_t addresses[] = {0x0000, 0x0001, 0x0002, 0x0003, 0x0DED, 0x0FED};
        size_t n = sizeof(addresses)/sizeof(addresses[0]);
        printf("EEPROM Verification Results:\n");
        for (size_t i = 0; i < n; ++i) {
            printf("EEPROM1[0x%04X] = 0x%02X\n", addresses[i], eeprom1[addresses[i]]);
            printf("EEPROM2[0x%04X] = 0x%02X\n", addresses[i], eeprom2[addresses[i]]);
        }
        return 0;
    }

    Burn & Verification

    • EEPROMs written with a GECU T48 programmer via minipro
    • ROM #1 programmed with high byte file, ROM #2 with low byte file
    • Multiple rewire/re-burn cycles until outputs matched expected values

    Milestone Achievement

    The Microcode Decoder is fully functional. It bridges the Program Counter and upcoming MDR/IR stages, converting opcodes and timing into precise control signals for the CPU.


    Engineering Methodology

    This build reinforced:

    • Correcting data representation early prevents cascading errors
    • PULSE_REQ improved timing integrity and latch reliability
    • Static signal verification with a multimeter can be more effective than a logic analyzer for certain tests
    • Pre-drafting future modules ensures coherent datapath planning

    Next Steps

    1. Memory Data Register (MDR) – temporary storage for memory read/writes
    2. Instruction Register (IR) – holds current opcode for decoding
    3. Memory Module & Register Module – completes the execution datapath
  • DINO CPU Project – Program Counter Implementation and Validation

    DINO CPU Project – Program Counter Implementation and Validation

    The Critical Address Generation Foundation

    With the ring counter establishing systematic timing coordination, the DINO CPU project reached a pivotal engineering milestone: implementing the 16-bit Program Counter that would serve as the addressing backbone for all instruction execution. This module demanded cascaded counter logic with bidirectional operation, preset capability, and clean bus arbitration – functionality that would make or break the entire discrete logic computer.

    The engineering challenge centered on coordinating four 74LS193 counters through 74LS245 bus transceivers while maintaining signal integrity across a complex 16-bit address architecture.


    Schematic Architecture and Component Analysis

    Strategic Component Selection

    The PC implementation required components that could handle complex addressing requirements:

    • 74LS193 Quad Counters: Chosen for bidirectional counting with independent up/down clocks and comprehensive preset functionality
    • 74LS245 Bus Transceivers: Essential for bidirectional bus control and output enable coordination
    • 74LS02 NOR Gate: Provides active-low signal inversion required for control word compatibility

    Circuit Complexity Evolution

    The schematic development represented the most intricate circuit design attempted to date. Initial architecture included a 74LS32 OR gate for PC_MUX decode logic, but systematic analysis revealed this was redundant – the control word matrix already provided the necessary logic states.

    This optimization eliminated unnecessary components while simplifying the signal routing:

    • Iteration 1: Complete counter cascade with redundant decode logic
    • Iteration 2: Streamlined design with OR gate removal and corrected DIR signals on output transceivers

    The final schematic achieved maximum functionality with minimal component count through careful architectural analysis.


    Systematic Testing Protocol Development

    Comprehensive Validation Framework

    Rather than hoping the complex circuit would work, a rigorous testing protocol was established before construction began:

    • Preset Operations: Verify PC responds correctly to PC_PRESET control activation
    • Increment Coordination: Validate carry propagation across all four 74LS193 stages
    • Decrement Functionality: Confirm borrow propagation through systematic countdown testing
    • Bus Arbitration: Ensure PC_MUX properly controls output transceiver states
    • Isolated Operation: Verify counter maintains function when bus outputs are disabled
    • Full-Range Capability: Test 16-bit counting across complete address space

    This methodology ensured any failures could be traced to specific subsystems rather than requiring wholesale circuit debugging.


    Construction Strategy and Pattern Recognition

    Wiring Complexity Management

    The 16-bit bus architecture demanded strategic construction planning beyond typical breadboard assembly:

    • Dupont Jumper Pre-Fitting: Temporary connections identified potential wire routing conflicts before permanent installation
    • Component Placement Optimization: Alternating input and output transceivers created natural wiring symmetries
    • Pattern-Based Routing: Systematic cascade connections reduced complexity through visual consistency

    Engineering Discovery

    The construction process revealed how thoughtful component arrangement transforms chaotic wiring into organized patterns. Alternating transceiver placement created identical routing for all cascade connections, turning potential complexity into systematic regularity.

    The result resembled engineered artwork – clean, predictable wire patterns that facilitated both construction and debugging.


    Validation Results and System Integration

    Logic Analyzer Verification

    Complete 16-bit bus monitoring provided comprehensive visibility into counter operations:

    • Immediate Success: All functionality operational on first power-up attempt
    • Clean Transitions: No timing glitches or signal integrity issues observed
    • Proper Cascading: Carry and borrow signals propagating correctly across all stages

    Timing Dependency Resolution

    Testing revealed critical insights about cascade signal timing requirements:

    • Manual Control Limitations: Hand-operated up/down controls provided insufficient pulse width for cascade operations
    • 555 Timer Integration: 60Hz clock delivered proper timing characteristics for ~BO/~CO signals
    • Engineering Insight: Cascade functionality depends on clock pulse duration, not merely edge timing

    Preset Capability Confirmation

    Address loading validation completed the testing sequence:

    • MSB Testing Strategy: Preset testing focused on high-order bits for immediate visual confirmation
    • Construction Error Discovery: Input transceivers inadvertently hardwired during assembly process
    • Rapid Resolution: Single connection correction restored full preset functionality

    Engineering Significance and System Foundation

    Complexity Management Success

    The PC implementation validated key embedded development principles:

    • Schematic-Driven Development: KiCAD circuit design prevented construction errors and enabled strategic component placement
    • Systematic Validation: Pre-construction testing framework eliminated debugging uncertainty
    • Methodical Assembly: Disciplined wiring approach prevented the chaos typical of complex breadboard circuits

    Architectural Foundation Establishment

    Successful PC operation provides the addressing infrastructure for complete CPU functionality:

    • Instruction Sequencing: Reliable program advancement enables systematic instruction execution cycles
    • Address Space Access: 16-bit capability provides substantial memory addressing range
    • Control Word Integration: PC_MUX and PC_PRESET signals interface cleanly with established timing architecture

    Methodology Validation

    This milestone demonstrated how systematic engineering practices produce reliable results on complex multi-chip coordination problems. The combination of thorough design analysis, strategic testing protocols, and disciplined construction yielded first-attempt success on challenging timing-dependent hardware.


    Development Trajectory: T0/T1 Decoder Implementation

    The proven Program Counter establishes reliable address generation for the next critical phase:

    • Universal Instruction Fetch: T0/T1 timing states will coordinate ROM-to-IR data movement
    • Address Matrix Formation: Instruction Register output combined with ring counter states for control word indexing
    • Bootstrap Sequence Architecture: Initial fetch capability enabling instruction execution without manual startup

    The PC success provides engineering confidence for tackling the address formation complexity ahead.

    Core Engineering Principle: Complex embedded systems achieve reliability through systematic subsystem validation before integration attempts. The Program Counter milestone exemplifies how disciplined analysis, careful construction, and comprehensive testing enable first-try success on demanding multi-chip timing coordination challenges.

    The discrete logic computer advances toward complete computational capability through proven engineering methodology.

  • DINO CPU Project – Ring Counter Implementation and Control Unit Architecture

    DINO CPU Project – Ring Counter Implementation and Control Unit Architecture

    From Theory to Working Hardware

    With the control unit revelation providing clear direction for systematic timing coordination, the next phase involved translating architectural understanding into working hardware. The ring counter represents the timing heart that enables control word coordination – transforming the theoretical framework into practical implementation.

    The goal was to build the systematic T0-T5 timing sequence that would drive control word lookups and instruction execution phases.

    Ring Counter Implementation

    Hardware Components

    • 74LS163: 4-bit synchronous counter (binary sequence generation)
    • 74LS138: 3-to-8 decoder (converts binary count to one-hot timing signals)
    • 74LS00: NAND gate (detects count=6 to trigger reset)
    • NE555P: Timer circuit (proven from previous sequencer design)

    Circuit Operation

    The implementation creates a systematic T0→T1→T2→T3→T4→T5→reset timing sequence:

    Reset Logic: When the counter reaches binary 110 (decimal 6), both QB and QC outputs go HIGH. The NAND gate detects this condition and outputs LOW, triggering the ‘163’s active-low CLR input. The counter immediately resets to 000, creating the ring behavior.

    Decoder Output Pattern: The ‘138 decoder creates the required one-hot sequence with active-low outputs:

    • 000 (T0): Y0=LOW → 0111 1111
    • 001 (T1): Y1=LOW → 1011 1111
    • 010 (T2): Y2=LOW → 1101 1111
    • 011 (T3): Y3=LOW → 1110 1111
    • 100 (T4): Y4=LOW → 1111 0111
    • 101 (T5): Y5=LOW → 1111 1011

    Logic Analyzer Validation

    The ring counter was validated using logic analyzer capture, confirming:

    • Six distinct timing states: Clean T0→T1→T2→T3→T4→T5 sequence
    • Reset behavior: 7th state triggers reset pulse, immediately returns to T0
    • Timing consistency: Each state lasts approximately 60ms (consistent with 555 timing)
    • Signal integrity: Clean edges, proper logic levels, no glitches
    • Stable operation: Continuous cycling without timing irregularities

    The systematic T0-T5 timing states provide the foundation needed for control word generation and instruction sequencing.

    Architecture Planning and Component Selection

    Control Unit Evolution

    The successful ring counter implementation enabled architectural planning for the complete control unit system:

    Memory Architecture Defined:

    • 0x0000-0x0FFF: Control word table (4KB)
    • 0x1000-0xFFFF: Program space (60KB)
    • Parallel AT28C256 ROMs: 16-bit control words and instructions

    Instruction Register Implementation:

    • Two 74LS373: 8-bit transparent latches configured for 16-bit instruction storage
    • T1 control: LE signal derived from inverted T1 timing state
    • Stable operation: Transparent during T1 (instruction fetch), latched during T2-T6 (execute)

    Expandability Considerations

    The current 6-state ring counter can be expanded to 7 states by changing the reset detection logic:

    • Current: Detect count=6 (QB AND QC)
    • Future: Detect count=7 (QB AND QC AND QD) using 74LS10 triple 3-input NAND

    Engineering Methodology Validation

    This implementation phase validated several critical embedded development practices:

    • Component isolation testing: Ring counter validated independently before system integration
    • Logic analyzer verification: Hardware-level visibility essential for timing validation
    • Systematic problem resolution: Theoretical analysis confirmed by practical measurement
    • Proven building blocks: Timer circuit preserved from working sequencer design

    Next Phase Preparation

    The ring counter milestone establishes the timing foundation for control word matrix implementation. With systematic T0-T5 timing generation validated, the next development phase involves:

    • Control word architecture: ROM-based lookup table implementation
    • Instruction register integration: 16-bit instruction storage and decode
    • Data path coordination: Register, ALU, and memory interface control

    The control unit timing heart is operational. The systematic approach from proven ring counter timing → control word architecture → complete CPU represents solid engineering methodology where each phase builds on validated previous work.

    Memory Architecture Discovery

    The ring counter implementation sparked investigation into memory organization and system architecture. Several key insights emerged:

    Data Flow Architecture: The systematic data movement follows ROM→RAM→Register pathways rather than direct ROM→Register connections. This staging approach enables proper timing coordination where ROM data is first loaded into RAM workspace, then selectively moved to registers during appropriate timing states. SRAM provides the essential intermediate storage that allows the control unit to coordinate complex multi-step data transfers, while registers (74LS373) provide the parallel access needed for immediate decoder input and ALU operations.

    Parallel ROM Configuration: Two AT28C256 ROMs configured in parallel create 32K × 16-bit memory space rather than 64KB total capacity. This configuration provides 16-bit instruction words and control words while maintaining single-address access. The parallel approach eliminates the complexity of interleaved addressing while maximizing control word capability.

    Memory Map Strategy: Partitioning the 32K address space into control word table (0x0000-0x0FFF) and program storage (0x1000-0xFFFF) enables systematic ROM utilization. The same physical ROM serves dual purposes through address decoding – control unit accesses lower addresses for timing coordination while program counter accesses higher addresses for instruction fetch.

    Pencil and Paper Phase

    With the timing foundation established and memory architecture understood, the next development phase requires stepping away from hardware implementation to focus on systematic program design. The ring counter provides reliable timing coordination, but defining what instructions to execute demands careful planning:

    Program Definition Requirements:

    • Basic instruction set specification (LOAD, ADD, OUT, HALT, JMP)
    • Control word definitions for each instruction timing phase
    • Data flow coordination between ROM, RAM, registers, and ALU
    • Memory organization for both program storage and control word lookup

    The hardware platform can execute any systematic instruction sequence, but creating meaningful programs requires understanding what computational tasks the discrete logic system should demonstrate.

    The transition from working timing hardware to systematic programming represents the shift from component validation to computer architecture implementation.

  • DINO CPU Project – The Control Unit Revelation

    DINO CPU Project – The Control Unit Revelation

    The Missing Architectural Piece

    After months of building discrete logic components in isolation—counters, memory interfaces, basic sequencers—the DINO CPU project had stalled at a fundamental level. Individual subsystems functioned correctly, but coordinating them into a working computer remained an elusive challenge. What I had dismissed as “simple switching logic” revealed itself as the most critical architectural component: systematic control coordination.

    The breakthrough came from stepping away from ad-hoc circuit assembly and studying proven computer architecture principles. Paul Malvino’s ( “Digital Computer Electronics” ) SAP-1 design provided the methodical approach my discrete logic implementation was missing.

    From Chaos to Coordination

    Previous attempts used SPDT switches and basic gate logic to coordinate bus access and memory operations. This approach worked for simple demonstrations but failed when multiple devices needed precise timing coordination. The fundamental issue wasn’t component selection—it was control system architecture.

    Real computers require systematic control word generation, not intuitive switching circuits. The control unit acts as conductor, orchestrating fetch-decode-execute cycles through precisely timed signal coordination.

    Ring Counter Implementation Discovery

    SAP-1’s control timing depends on sequential states T0→T1→T2→T3→T4→T5→T0 that coordinate instruction phases. Initial component research focused on 74LS164 shift registers, but availability constraints demanded alternative approaches.

    The solution emerged from standard TTL components:

    • 74S163: 4-bit synchronous counter (binary sequence 0-5, then reset)
    • 74LS138: 3-to-8 decoder (converts binary count to one-hot timing signals)
    • 74LS00: NAND gate (detects count=6 to trigger reset)

    Reset Logic: When the counter reaches binary 110 (decimal 6), both QB and QC outputs go HIGH. The NAND gate detects this condition and outputs LOW, triggering the 163’s active-low CLR input. The counter immediately resets to 000, creating the ring behavior.

    Truth Table Verification: The 74LS138 decoder creates exactly the one-hot sequence required:

    Counter Input → Decoder Output (Active LOW)
    000 → Y0 (T0 timing state)
    001 → Y1 (T1 timing state)
    010 → Y2 (T2 timing state)
    011 → Y3 (T3 timing state)
    100 → Y4 (T4 timing state)
    101 → Y5 (T5 timing state)

    Control Word Architecture Breakthrough

    The ring counter provides timing states, but SAP-1’s intelligence comes from translating those states into specific control operations. Each timing state generates an 8-bit control word that enables or disables specific system functions.

    Universal Fetch Cycle (T0-T2):

    • T0: Program counter drives address bus, memory read enabled
    • T1: Increment program counter
    • T2: Load instruction register from data bus

    Instruction-Specific Execute Cycle (T3-T5):

    • Varies by instruction type (LDA, ADD, OUT, etc.)
    • Different control signals active based on operation requirements
    • Same timing framework, different control word patterns

    ROM-Based Control Matrix: Instead of implementing Malvino’s discrete gate logic, modern EEPROM provides elegant lookup table functionality. Address formation combines instruction opcode with timing state: [Instruction bits][Timing state bits] = ROM address. The data at that address contains the exact control word needed for that specific (instruction, timing) combination.

    Historical Perspective

    This revelation sparked appreciation for the intellectual journey from abstract mathematics to physical computation. George Boole’s Boolean algebra (1854) provided the mathematical foundation, Claude Shannon’s switching theory thesis (1937) connected those abstractions to physical circuits, and now discrete TTL components implement those same principles on the breadboard.

    It’s been a journey standing on the shoulders of giants who transformed pure logic into computational reality.

    Engineering Insight

    The control unit isn’t just another subsystem—it’s the architectural element that transforms individual components into a coordinated computer. Understanding this principle bridges the gap between discrete logic experimentation and real processor design fundamentals.

    Modern processors use identical fetch-decode-execute principles, just implemented in silicon with enhanced complexity. The same control timing concepts scale from SAP-1’s 6 states to modern processors’ 15-20 pipeline stages.

    Next Phase Implementation

    With control timing architecture understood, the next development phase involves:

    • Mapping complete data paths between SRAM, registers, ALU, and output systems
    • Defining all control signal requirements and bus arbitration logic
    • Implementing ROM-based control matrix using 28C256 EEPROM
    • Creating control word definitions for SAP-1’s basic instruction set

    The control unit mystery has been solved. Now it’s systematic engineering execution to bring the discrete logic computer to life.

  • DINO CPU Project: Building an 8-Bit Computer from Discrete Logic

    DINO CPU Project: Building an 8-Bit Computer from Discrete Logic

    The Challenge that Started Everything

    After mastering bare-metal C programming and wrestling with the RP2040’s ROM assumptions in my OTA bootloader project, a fundamental question emerged: what happens below the microcontroller abstraction layer? Modern MCUs hide extraordinary complexity behind simple APIs – but understanding computation from first principles required going deeper.

    The DINO CPU project represents an attempt to build computational capability using only discrete logic components – counters, memory, ALU chips, and control logic. No microcontrollers, no firmware, just the fundamental building blocks that make computation possible.

    What I Set Out to Build

    System Architecture:

    • 8-bit data path with 16-bit addressing capability
    • Von Neumann architecture (shared instruction/data memory)
    • 32KB addressable memory space
    • Real-world application: Thermistor temperature monitoring with digital display and analog output

    Component Foundation:

    • Memory: MCM60256AP-10 32KB SRAM for program storage
    • Program Counter: SN74LS590N 8-bit counters chained for 16-bit addressing
    • Bus Control: 74LS645N octal transceiver for bus arbitration
    • Clock Generation: 555 timer providing controlled system timing
    • ALU: 74F382N 8-bit arithmetic logic unit for computation

    The goal wasn’t just to blink LEDs – it was to create a system capable of reading temperature sensors, performing calculations, and driving both digital displays and analog outputs.

    The Engineering Reality

    Phase 1: The Deceptively Simple Beginning

    The initial approach seemed straightforward: build a CPU-free sequencer that could step through memory addresses and display stored patterns on LEDs. Two modes: LOAD (program data via DIP switches) and RUN (execute stored sequence).

    Early Success Indicators:

    • Clean 16-bit address generation from chained counters
    • Successful SRAM read/write operations
    • Mode switching between programming and execution
    • LED patterns displaying correctly

    The basic sequencer worked exactly as designed. I could manually program LED chase sequences, store them in SRAM, and watch them execute reliably. This initial success masked the complexity that lay ahead.

    The Control Logic Revelation

    What initially appeared as simple mode switching (LOAD vs. RUN) revealed itself as a fundamental architectural challenge. The moment I attempted to coordinate multiple bus devices – DIP switches, SRAM, and LED displays – the limitations of my approach became clear.

    Bus Arbitration Issues: DIP switches provided weak logic levels insufficient for reliable SRAM write operations. The 74LS645 bus transceiver required precise timing coordination that simple SPDT switches couldn’t provide. Signal integrity problems emerged immediately.

    Interdependency Testing: Components couldn’t be validated independently due to circular dependencies between memory interface and mode control logic. The SRAM operation depended on proper bus control, but bus control verification required working SRAM access.

    Control Logic Complexity: What I had designed as simple combinational logic – AND gates and switches – proved inadequate for coordinating multiple bus devices with different timing requirements.

    The Architecture Limitation

    The fundamental issue wasn’t component selection or circuit construction – it was control system architecture. Real computers require systematic control word generation, not ad-hoc switching logic.

    Control Word Requirements:

    • Coordinated timing for instruction fetch, decode, and execute cycles
    • Bus arbitration preventing multiple drivers
    • Sequence management for multi-cycle operations
    • Error handling and state recovery

    My initial design using SPDT switches and basic gates couldn’t generate the sophisticated control signals required for reliable computer operation.

    The Strategic Pivot

    Reference Architecture Investigation

    Rather than abandoning the project, I shifted to studying proven methodologies. Albert Paul Malvino’s “Digital Computer Electronics” and the SAP (Simple As Possible) computer architecture provided the systematic approach my initial design lacked.

    Key Insights from SAP-1:

    • Control logic requires state machines, not simple combinational circuits
    • Instruction cycles need multiple clock phases with coordinated timing
    • Bus control demands systematic enable/disable sequencing
    • Memory operations require setup and hold time management

    Engineering Maturity Recognition

    The project revealed a critical gap in my engineering approach. I had been pattern-matching from successful circuits without understanding the underlying control theory that makes computers reliable.

    Methodology Evolution:

    • From ad-hoc circuit assembly to systematic control design
    • From hoping circuits work to proving they meet timing requirements
    • From debugging failures to preventing them through proper design
    • From component-focused to system-focused engineering

    Current Status and Lessons Learned

    Preserved Working Elements

    The investigation wasn’t a complete loss. Several subsystems function correctly and provide a foundation for systematic reconstruction:

    • Validated 16-bit program counter implementation with proper chaining
    • Functional SRAM read/write interface with verified timing margins
    • Working power distribution and signal conditioning circuits
    • Proven component selection appropriate for the target application

    Knowledge Gained

    Signal Integrity Requirements: Real-world digital logic demands attention to current sourcing, logic levels, and bus loading effects that breadboard prototypes often hide.

    Control System Architecture: Computer control logic requires systematic state machine design, not intuitive switching circuits.

    Timing Analysis Methodology: Reliable digital systems need verified setup/hold times, not just “fast enough” clock speeds.

    Modular Design Discipline: Complex systems require independently testable subsystems with well-defined interfaces.

    The Engineering Insight

    This project exemplifies how the most valuable learning emerges from systematic analysis of apparent failures. What began as frustration with non-working circuits became comprehensive understanding of computer architecture principles.

    The investigation process – methodical debugging, component-level testing, and willingness to study fundamental theory when initial approaches failed – proved more valuable than any working computer would have been initially.

    Future Direction

    Systematic Reconstruction Plan

    The project continues with enhanced methodology, combining original architectural goals with proven control system design principles:

    Immediate Objectives:

    1. Document current system state and verified component functionality
    2. Study SAP-1 control logic principles and timing methodology
    3. Design modular test interfaces for independent subsystem validation
    4. Implement systematic control word generation using proven techniques
    5. Rebuild with emphasis on testable, verifiable operation

    Long-term Vision:

    • Complete 8-bit computer capable of thermistor monitoring application
    • Systematic documentation enabling others to understand and replicate
    • Foundation for exploring advanced computer architecture concepts
    • Platform for investigating computation principles from silicon upward

    Engineering Philosophy Evolution

    The DINO project transformed my understanding of embedded systems engineering. Previous projects succeeded despite gaps in fundamental knowledge. This project exposed those gaps and provided the motivation to fill them systematically.

    Key Realization: Understanding why systems work matters more than just making them work. The debugging methodology, control theory insights, and systematic design principles gained here enable confident approaches to any digital logic challenge.

    Project Significance

    DINO represents more than an attempt to build a computer – it embodies the engineering discipline of understanding computational systems from first principles. The systematic analysis of control logic requirements, timing constraints, and system architecture provides knowledge applicable far beyond discrete logic projects.

    The project continues as a long-term educational investment, combining practical engineering with fundamental computer science concepts. Understanding computation at the silicon level informs every higher-level embedded project that follows.