Skip to content
LAM
Read Home Blog
Make Projects HTML Tools Games
Touch grass Notes Resume Links
Home Blog HTML Projects
Tools Games Notes Resume Links
Back CSE 230: Datapath Architect Programming
Download Open
Show description 911 chars · Programming

CSE 230: Datapath Architect

CSE 230: Datapath Architect






Datapath Architect CSE 230




Single-Cycle MIPS Simulator









Instruction Type

R-Type (add, sub, and, or)
Load Word (lw)
Store Word (sw)
Branch Equal (beq)





Operation / Function






Registers (rs, rt, rd)










Immediate / Offset (Hex)





add $t0, $t1, $t2



EXECUTE CYCLE
RESET MACHINE


Theory: In a single-cycle datapath, the entire instruction (Fetch, Decode, Execute, Memory, Writeback) completes in one clock tick. The Control Unit sets the multiplexers based on the Opcode.



















PC


IM


RegFile


Control


ALU Ctrl


ALU


DM

































Control Signals


RegDst0


ALUSrc0


MemtoReg0


RegWrite0


MemRead0


MemWrite0


Branch0


ALUOp00





Register File


Reg
Val (Dec)

CSE 230: Datapath Architect

25,055 bytes · HTML source
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CSE 230: Datapath Architect</title>
    <style>
        :root {
            --bg-dark: #0f172a;
            --bg-panel: rgba(30, 41, 59, 0.7);
            --text-main: #e2e8f0;
            --text-muted: #94a3b8;
            --accent-cyan: #06b6d4;
            --accent-purple: #a855f7;
            --accent-green: #22c55e;
            --accent-red: #ef4444;
            --wire-inactive: #334155;
            --font-ui: 'Inter', system-ui, sans-serif;
            --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
        }

        * { box-sizing: border-box; }

        body {
            margin: 0;
            padding: 0;
            background-color: var(--bg-dark);
            color: var(--text-main);
            font-family: var(--font-ui);
            overflow: hidden;
            height: 100vh;
            display: flex;
            flex-direction: column;
        }

        /* --- Header --- */
        header {
            padding: 1rem 2rem;
            border-bottom: 1px solid rgba(255,255,255,0.1);
            display: flex;
            justify-content: space-between;
            align-items: center;
            background: rgba(15, 23, 42, 0.9);
            backdrop-filter: blur(10px);
            z-index: 10;
        }

        h1 { margin: 0; font-size: 1.25rem; letter-spacing: 1px; color: var(--accent-cyan); text-transform: uppercase; }
        .badge { font-size: 0.75rem; background: var(--accent-purple); color: white; padding: 2px 8px; border-radius: 4px; margin-left: 10px; }

        /* --- Main Layout --- */
        .dashboard {
            display: grid;
            grid-template-columns: 300px 1fr 300px;
            flex: 1;
            overflow: hidden;
        }

        /* --- Sidebar: Controls --- */
        .sidebar-left {
            padding: 1.5rem;
            background: var(--bg-panel);
            border-right: 1px solid rgba(255,255,255,0.05);
            overflow-y: auto;
            display: flex;
            flex-direction: column;
            gap: 1.5rem;
        }

        .control-group { display: flex; flex-direction: column; gap: 0.5rem; }
        label { font-size: 0.85rem; color: var(--text-muted); font-weight: 600; text-transform: uppercase; }
        
        select, button, input {
            background: rgba(0,0,0,0.3);
            border: 1px solid rgba(255,255,255,0.1);
            color: var(--text-main);
            padding: 0.75rem;
            border-radius: 6px;
            font-family: var(--font-mono);
            font-size: 0.9rem;
            cursor: pointer;
            transition: all 0.2s;
        }

        select:focus, input:focus { outline: none; border-color: var(--accent-cyan); }
        
        button.primary {
            background: linear-gradient(45deg, var(--accent-cyan), #3b82f6);
            border: none;
            color: black;
            font-weight: bold;
            box-shadow: 0 0 15px rgba(6, 182, 212, 0.3);
        }
        button.primary:hover { box-shadow: 0 0 25px rgba(6, 182, 212, 0.5); transform: translateY(-1px); }

        .instruction-preview {
            font-family: var(--font-mono);
            background: black;
            padding: 1rem;
            border-radius: 6px;
            border-left: 3px solid var(--accent-green);
            font-size: 0.9rem;
        }

        /* --- Center: Visualization --- */
        .viz-stage {
            position: relative;
            background-image: radial-gradient(circle at 50% 50%, #1e293b 1px, transparent 1px);
            background-size: 20px 20px;
            display: flex;
            justify-content: center;
            align-items: center;
            overflow: hidden; /* For pan/zoom if added later */
        }

        /* SVG Styles */
        svg {
            width: 95%;
            height: 95%;
            max-width: 1000px;
        }

        .component { fill: rgba(30, 41, 59, 0.9); stroke: var(--text-muted); stroke-width: 2; }
        .component-text { fill: var(--text-main); font-family: var(--font-ui); font-size: 12px; font-weight: bold; text-anchor: middle; dominant-baseline: middle; pointer-events: none; }
        
        .wire { fill: none; stroke: var(--wire-inactive); stroke-width: 2; transition: stroke 0.3s, stroke-width 0.3s; }
        .wire.active { stroke: var(--accent-cyan); stroke-width: 3; filter: drop-shadow(0 0 5px var(--accent-cyan)); }
        .wire.control { stroke: var(--wire-inactive); stroke-dasharray: 4; }
        .wire.control.active { stroke: var(--accent-purple); filter: drop-shadow(0 0 5px var(--accent-purple)); animation: flow 1s linear infinite; }

        .mux { fill: #334155; stroke: var(--text-muted); }
        
        @keyframes flow {
            to { stroke-dashoffset: -20; }
        }

        /* --- Sidebar: Registers & Signals --- */
        .sidebar-right {
            padding: 1.5rem;
            background: var(--bg-panel);
            border-left: 1px solid rgba(255,255,255,0.05);
            overflow-y: auto;
            font-family: var(--font-mono);
        }

        .data-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; margin-bottom: 2rem; }
        .data-table th { text-align: left; color: var(--accent-cyan); padding-bottom: 0.5rem; border-bottom: 1px solid rgba(255,255,255,0.1); }
        .data-table td { padding: 0.4rem 0; border-bottom: 1px solid rgba(255,255,255,0.05); }
        .data-table .val-changed { color: var(--accent-green); animation: flash 1s; }

        .signal-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
        .signal-box { background: rgba(0,0,0,0.3); padding: 0.5rem; border-radius: 4px; text-align: center; border: 1px solid transparent; }
        .signal-box.active { border-color: var(--accent-purple); color: var(--accent-purple); box-shadow: 0 0 10px rgba(168, 85, 247, 0.2); }
        .signal-label { display: block; font-size: 0.7rem; color: var(--text-muted); }
        .signal-val { font-weight: bold; font-size: 0.9rem; }

        @keyframes flash {
            0% { color: white; text-shadow: 0 0 10px white; }
            100% { color: var(--accent-green); }
        }

        /* Tooltip */
        .tooltip {
            position: absolute;
            background: rgba(0,0,0,0.9);
            border: 1px solid var(--accent-cyan);
            padding: 0.5rem;
            border-radius: 4px;
            font-size: 0.8rem;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.2s;
            z-index: 100;
        }

    </style>
</head>
<body>

    <header>
        <div>
            <h1>Datapath Architect <span class="badge">CSE 230</span></h1>
        </div>
        <div style="font-size: 0.8rem; color: var(--text-muted);">
            Single-Cycle MIPS Simulator
        </div>
    </header>

    <div class="dashboard">
        
        <div class="sidebar-left">
            <div class="control-group">
                <label>Instruction Type</label>
                <select id="instrType">
                    <option value="R-Type">R-Type (add, sub, and, or)</option>
                    <option value="LW">Load Word (lw)</option>
                    <option value="SW">Store Word (sw)</option>
                    <option value="BEQ">Branch Equal (beq)</option>
                </select>
            </div>

            <div class="control-group">
                <label>Operation / Function</label>
                <select id="opcodeSelect">
                    </select>
            </div>

            <div class="control-group">
                <label>Registers (rs, rt, rd)</label>
                <div style="display: flex; gap: 5px;">
                    <select id="rs" class="reg-select"></select>
                    <select id="rt" class="reg-select"></select>
                    <select id="rd" class="reg-select"></select>
                </div>
            </div>

            <div class="control-group" id="immGroup" style="display:none;">
                <label>Immediate / Offset (Hex)</label>
                <input type="text" id="immediate" value="0x0004" maxlength="6">
            </div>

            <div class="instruction-preview" id="asmPreview">
                add $t0, $t1, $t2
            </div>

            <button class="primary" onclick="executeCycle()">EXECUTE CYCLE</button>
            <button onclick="resetMachine()">RESET MACHINE</button>

            <div style="margin-top: auto; font-size: 0.8rem; color: #64748b; line-height: 1.4;">
                <strong style="color:white;">Theory:</strong> In a single-cycle datapath, the entire instruction (Fetch, Decode, Execute, Memory, Writeback) completes in one clock tick. The <strong>Control Unit</strong> sets the multiplexers based on the Opcode.
            </div>
        </div>

        <div class="viz-stage">
            <div id="tooltip" class="tooltip"></div>
            <svg viewBox="0 0 800 500" id="datapathSvg">
                <defs>
                    <marker id="arrow" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto" markerUnits="strokeWidth">
                        <path d="M0,0 L0,6 L9,3 z" fill="#334155" />
                    </marker>
                    <marker id="arrow-active" markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto" markerUnits="strokeWidth">
                        <path d="M0,0 L0,6 L9,3 z" fill="#06b6d4" />
                    </marker>
                </defs>

                <rect x="50" y="200" width="40" height="60" class="component" />
                <text x="70" y="230" class="component-text">PC</text>

                <rect x="150" y="150" width="80" height="120" class="component" />
                <text x="190" y="210" class="component-text">IM</text>

                <rect x="350" y="150" width="80" height="120" class="component" />
                <text x="390" y="210" class="component-text">RegFile</text>

                <ellipse cx="250" cy="80" rx="40" ry="30" class="component" style="stroke: var(--accent-purple);" />
                <text x="250" y="80" class="component-text" style="fill: var(--accent-purple);">Control</text>

                <ellipse cx="480" cy="350" rx="30" ry="20" class="component" style="stroke: var(--accent-purple);" />
                <text x="480" y="350" class="component-text" style="font-size: 10px;">ALU Ctrl</text>

                <path d="M480,180 L480,260 L540,240 L540,200 Z" class="component" />
                <text x="510" y="220" class="component-text">ALU</text>

                <rect x="600" y="180" width="80" height="100" class="component" />
                <text x="640" y="230" class="component-text">DM</text>

                <path d="M310,230 L310,270 L330,270 L330,230 Z" class="mux" id="mux-regdst" />
                <path d="M450,230 L450,270 L470,270 L470,230 Z" class="mux" id="mux-alusrc" />
                <path d="M720,200 L720,240 L740,240 L740,200 Z" class="mux" id="mux-memtoreg" />

                <path d="M90,230 L150,230" class="wire" id="w-pc-im" />
                
                <path d="M230,190 L350,190" class="wire" id="w-im-reg1" />
                <path d="M230,210 L350,210" class="wire" id="w-im-reg2" />
                <path d="M230,170 L250,170 L250,110" class="wire control" id="w-im-control" />
                <path d="M230,230 L310,240" class="wire" id="w-im-muxreg-0" />
                <path d="M230,250 L310,260" class="wire" id="w-im-muxreg-1" />
                <path d="M230,270 L400,270 L400,260 L450,260" class="wire" id="w-im-signext" />

                <path d="M430,190 L480,190" class="wire" id="w-reg-alu1" />
                <path d="M430,230 L450,240" class="wire" id="w-reg-muxalu" />
                
                <path d="M470,250 L480,250" class="wire" id="w-muxalu-alu" />

                <path d="M540,220 L600,220" class="wire" id="w-alu-dm-addr" />
                <path d="M540,220 L560,220 L560,160 L710,160 L710,210 L720,210" class="wire" id="w-alu-muxmem-0" />
                
                <path d="M430,230 L440,230 L440,300 L600,300 L600,270" class="wire" id="w-reg-dm-data" />

                <path d="M680,230 L720,230" class="wire" id="w-dm-muxmem-1" />

                <path d="M740,220 L760,220 L760,380 L300,380 L300,250 L350,250" class="wire" id="w-wb-reg" />

                <path d="M290,80 L320,80 L320,220" class="wire control" id="c-regdst" /> <path d="M270,110 L270,350 L460,350" class="wire control" id="c-aluop" /> <path d="M250,50 L460,50 L460,220" class="wire control" id="c-alusrc" /> <path d="M230,110 L230,420 L620,420 L620,280" class="wire control" id="c-memwrite" /> <path d="M210,90 L200,90 L200,440 L660,440 L660,280" class="wire control" id="c-memread" /> <path d="M290,70 L730,70 L730,190" class="wire control" id="c-memtoreg" /> <path d="M290,90 L370,90 L370,140" class="wire control" id="c-regwrite" /> </svg>
        </div>

        <div class="sidebar-right">
            <h3>Control Signals</h3>
            <div class="signal-grid" id="signalGrid">
                <div class="signal-box" id="sig-regdst"><span class="signal-label">RegDst</span><div class="signal-val">0</div></div>
                <div class="signal-box" id="sig-alusrc"><span class="signal-label">ALUSrc</span><div class="signal-val">0</div></div>
                <div class="signal-box" id="sig-memtoreg"><span class="signal-label">MemtoReg</span><div class="signal-val">0</div></div>
                <div class="signal-box" id="sig-regwrite"><span class="signal-label">RegWrite</span><div class="signal-val">0</div></div>
                <div class="signal-box" id="sig-memread"><span class="signal-label">MemRead</span><div class="signal-val">0</div></div>
                <div class="signal-box" id="sig-memwrite"><span class="signal-label">MemWrite</span><div class="signal-val">0</div></div>
                <div class="signal-box" id="sig-branch"><span class="signal-label">Branch</span><div class="signal-val">0</div></div>
                <div class="signal-box" id="sig-aluop"><span class="signal-label">ALUOp</span><div class="signal-val">00</div></div>
            </div>

            <h3 style="margin-top: 2rem;">Register File</h3>
            <table class="data-table">
                <thead><tr><th>Reg</th><th>Val (Dec)</th></tr></thead>
                <tbody id="regTableBody">
                    </tbody>
            </table>
        </div>

    </div>

    <script>
        // --- System State ---
        const registers = Array(10).fill(0); // $zero to $t9 simplified
        const regNames = ['$zero', '$at', '$v0', '$v1', '$a0', '$a1', '$a2', '$a3', '$t0', '$t1'];
        // Initial values for demo
        registers[8] = 10; // $t0
        registers[9] = 20; // $t1

        // --- DOM Elements ---
        const els = {
            instrType: document.getElementById('instrType'),
            opcodeSelect: document.getElementById('opcodeSelect'),
            rs: document.getElementById('rs'),
            rt: document.getElementById('rt'),
            rd: document.getElementById('rd'),
            immGroup: document.getElementById('immGroup'),
            immediate: document.getElementById('immediate'),
            asmPreview: document.getElementById('asmPreview'),
            regTable: document.getElementById('regTableBody'),
            signals: {
                regdst: document.getElementById('sig-regdst'),
                alusrc: document.getElementById('sig-alusrc'),
                memtoreg: document.getElementById('sig-memtoreg'),
                regwrite: document.getElementById('sig-regwrite'),
                memread: document.getElementById('sig-memread'),
                memwrite: document.getElementById('sig-memwrite'),
                branch: document.getElementById('sig-branch'),
                aluop: document.getElementById('sig-aluop'),
            }
        };

        // --- Initialization ---
        function init() {
            // Populate Registers Dropdowns
            const createOpt = (name, idx) => `<option value="${idx}">${name}</option>`;
            const options = regNames.map((n, i) => createOpt(n, i)).join('');
            els.rs.innerHTML = options;
            els.rt.innerHTML = options;
            els.rd.innerHTML = options;

            // Set default selections
            els.rs.value = 8; // $t0
            els.rt.value = 9; // $t1
            els.rd.value = 8; // $t0

            updateOpcodeOptions();
            renderRegisters();
            updatePreview();
        }

        // --- Event Listeners ---
        els.instrType.addEventListener('change', () => {
            updateOpcodeOptions();
            updateUIForType();
            updatePreview();
        });
        
        [els.opcodeSelect, els.rs, els.rt, els.rd, els.immediate].forEach(el => {
            el.addEventListener('input', updatePreview);
        });

        // --- Logic ---
        function updateOpcodeOptions() {
            const type = els.instrType.value;
            let ops = [];
            if (type === 'R-Type') ops = ['add', 'sub', 'and', 'or', 'slt'];
            else if (type === 'LW') ops = ['lw'];
            else if (type === 'SW') ops = ['sw'];
            else if (type === 'BEQ') ops = ['beq'];

            els.opcodeSelect.innerHTML = ops.map(op => `<option value="${op}">${op}</option>`).join('');
        }

        function updateUIForType() {
            const type = els.instrType.value;
            // R-Type uses rd, others use immediate
            if (type === 'R-Type') {
                els.rd.style.display = 'inline-block';
                els.immGroup.style.display = 'none';
            } else {
                els.rd.style.display = 'none';
                els.immGroup.style.display = 'block';
            }
        }

        function updatePreview() {
            const op = els.opcodeSelect.value;
            const rsName = regNames[els.rs.value];
            const rtName = regNames[els.rt.value];
            const rdName = regNames[els.rd.value];
            const imm = els.immediate.value;

            let asm = "";
            if (els.instrType.value === 'R-Type') {
                asm = `${op} ${rdName}, ${rsName}, ${rtName}`;
            } else if (els.instrType.value === 'LW' || els.instrType.value === 'SW') {
                asm = `${op} ${rtName}, ${imm}(${rsName})`;
            } else if (els.instrType.value === 'BEQ') {
                asm = `${op} ${rsName}, ${rtName}, ${imm}`;
            }
            els.asmPreview.innerText = asm;
        }

        function renderRegisters() {
            els.regTable.innerHTML = registers.map((val, i) => `
                <tr>
                    <td style="color:var(--accent-cyan)">${regNames[i]}</td>
                    <td id="reg-val-${i}">${val}</td>
                </tr>
            `).join('');
        }

        function resetMachine() {
            resetWires();
            resetSignals();
            registers.fill(0);
            registers[8] = 10;
            registers[9] = 20;
            renderRegisters();
        }

        function resetWires() {
            document.querySelectorAll('.wire').forEach(w => {
                w.classList.remove('active');
            });
            document.querySelectorAll('.wire.control').forEach(w => {
                w.classList.remove('active');
            });
        }

        function resetSignals() {
            Object.values(els.signals).forEach(el => {
                el.classList.remove('active');
                el.querySelector('.signal-val').innerText = '0';
            });
        }

        // --- Core Simulation ---
        function executeCycle() {
            resetWires();
            
            const type = els.instrType.value;
            const op = els.opcodeSelect.value;
            const rsIdx = parseInt(els.rs.value);
            const rtIdx = parseInt(els.rt.value);
            const rdIdx = parseInt(els.rd.value);

            // 1. Fetch Stage (Always Active)
            highlight(['w-pc-im', 'w-im-reg1', 'w-im-reg2', 'w-im-control']);

            // 2. Decode / Control Unit
            const signals = getControlSignals(type);
            updateControlDisplay(signals);

            // 3. Execution Flow based on Type
            if (type === 'R-Type') {
                // Read Registers
                highlight(['w-reg-alu1', 'w-reg-muxalu', 'w-muxalu-alu']);
                
                // ALU Op
                const res = aluCalc(op, registers[rsIdx], registers[rtIdx]);
                
                // Write Back
                highlight(['w-alu-muxmem-0', 'w-wb-reg']);
                if (rdIdx !== 0) { // Can't write to $zero
                    registers[rdIdx] = res;
                    flashRegister(rdIdx);
                }

            } else if (type === 'LW') {
                // Read Base Addr
                highlight(['w-reg-alu1', 'w-im-signext', 'w-muxalu-alu']);
                
                // Mem Access
                highlight(['w-alu-dm-addr', 'w-dm-muxmem-1', 'w-wb-reg']);
                
                // Fake Memory Load (random or static for demo)
                const memVal = 42; 
                if (rtIdx !== 0) {
                    registers[rtIdx] = memVal;
                    flashRegister(rtIdx);
                }

            } else if (type === 'SW') {
                // Calc Addr & Read Data
                highlight(['w-reg-alu1', 'w-im-signext', 'w-muxalu-alu', 'w-reg-dm-data']);
                
                // Write to Mem (End of path)
                highlight(['w-alu-dm-addr']);
                // Logic: registers[rtIdx] written to Mem[rsIdx + imm]
            
            } else if (type === 'BEQ') {
                // Compare
                highlight(['w-reg-alu1', 'w-reg-muxalu', 'w-muxalu-alu']);
                // Branch Logic (Simplified visual)
                if (registers[rsIdx] === registers[rtIdx]) {
                    // Branch taken
                }
            }

            renderRegisters();
        }

        function getControlSignals(type) {
            // Simplified MIPS Control Truth Table
            if (type === 'R-Type') return { regdst: 1, alusrc: 0, memtoreg: 0, regwrite: 1, memread: 0, memwrite: 0, branch: 0, aluop: '10' };
            if (type === 'LW')     return { regdst: 0, alusrc: 1, memtoreg: 1, regwrite: 1, memread: 1, memwrite: 0, branch: 0, aluop: '00' };
            if (type === 'SW')     return { regdst: 'X', alusrc: 1, memtoreg: 'X', regwrite: 0, memread: 0, memwrite: 1, branch: 0, aluop: '00' };
            if (type === 'BEQ')    return { regdst: 'X', alusrc: 0, memtoreg: 'X', regwrite: 0, memread: 0, memwrite: 0, branch: 1, aluop: '01' };
        }

        function updateControlDisplay(sigs) {
            for (const [key, val] of Object.entries(sigs)) {
                const el = els.signals[key];
                el.querySelector('.signal-val').innerText = val;
                
                // Highlight wire in SVG if signal is 1
                if (val === 1 || val === '10' || val === '01') {
                    el.classList.add('active');
                    const wire = document.getElementById(`c-${key}`);
                    if(wire) wire.classList.add('active');
                } else {
                    el.classList.remove('active');
                }
            }
        }

        function highlight(ids) {
            ids.forEach(id => {
                const el = document.getElementById(id);
                if (el) el.classList.add('active');
            });
        }

        function aluCalc(op, v1, v2) {
            if (op === 'add') return v1 + v2;
            if (op === 'sub') return v1 - v2;
            if (op === 'and') return v1 & v2;
            if (op === 'or') return v1 | v2;
            if (op === 'slt') return (v1 < v2) ? 1 : 0;
            return 0;
        }

        function flashRegister(idx) {
            const cell = document.getElementById(`reg-val-${idx}`);
            if (cell) {
                cell.classList.remove('val-changed');
                void cell.offsetWidth; // trigger reflow
                cell.classList.add('val-changed');
            }
        }

        // Run
        init();

    </script>
</body>
</html>