{"id":31,"date":"2026-03-01T19:32:17","date_gmt":"2026-03-01T19:32:17","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=31"},"modified":"2026-07-11T06:47:12","modified_gmt":"2026-07-11T06:47:12","slug":"truth-table-generator","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/truth-table-generator\/","title":{"rendered":"Truth Table Generator | Generate, Compare &amp; Analyse Boolean Logic Offline"},"content":{"rendered":"\n<div class=\"pth-hero-section\">\n    <div class=\"pth-hero-content\">\n        <h2>Truth Table Studio<\/h2>\n        <p>Instantly generate truth tables, simplify Boolean logic, and convert expressions to NAND\/NOR gates with Verilog HDL code.<\/p>\n\n        <div id=\"pth-toc-placeholder\"><\/div>\n    <\/div>\n\n<div class=\"pth-hero-image\">\n    <img data-no-lazy=\"1\"\n         src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/03\/Truth-Table-Generator-1-800x447.jpeg\"\n         width=\"800\"\n         height=\"447\"\n         alt=\"Truth Table Studio\"\n         fetchpriority=\"high\"\n         loading=\"eager\"\n         decoding=\"async\"\n         style=\"width:100%; height:auto; display:block;\">\n  <\/div>\n<\/div>\n\n\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#\ud83d\udd34-when-the-logic-works-on-paper-but-not-on-the-breadboard\">\ud83d\udd34\u00a0When the logic works on paper but not on the breadboard<\/a><\/li><li><a href=\"#\ud83d\udfe1-proving-a-simplification-did-not-change-the-circuit\">\ud83d\udfe1\u00a0Proving a simplification did not change the circuit<\/a><\/li><li><a href=\"#\ud83d\udfe2-the-same-table-as-terms-as-waves-and-as-a-warning\">\ud83d\udfe2\u00a0The same table as terms, as waves, and as a warning<\/a><ul><li><a href=\"#\ud83d\udfe2-the-check-that-pays-for-itself-redundant-variables\">\ud83d\udfe2\u00a0The check that pays for itself: redundant variables<\/a><\/li><\/ul><\/li><li><a href=\"#\ud83d\udd34-honest-limits-and-where-to-go-next\">\ud83d\udd34\u00a0Honest limits, and where to go next<\/a><\/li><\/ul><\/nav><\/div>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<div id=\"pth-tt-studio-wrapper\">\r\n    <style>\r\n        #pth-tt-studio-wrapper { box-sizing: border-box; font-family: 'Inter', system-ui, -apple-system, sans-serif; color: #1e293b; background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; margin: 20px 0; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); }\r\n        #pth-tt-studio-wrapper * { box-sizing: border-box; min-width: 0; }\r\n\r\n        #pth-tt-studio-wrapper .pth-topbar { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; padding: 20px 24px 0; }\r\n        #pth-tt-studio-wrapper .pth-title { margin: 0; font-size: 1.35rem; font-weight: 800; color: #0f172a; }\r\n        #pth-tt-studio-wrapper .pth-toolbar { display: flex; gap: 8px; flex-wrap: wrap; }\r\n        #pth-tt-studio-wrapper .pth-btn { border: none; padding: 8px 14px; font-size: 0.85rem; border-radius: 7px; cursor: pointer; font-weight: 700; font-family: inherit; display: inline-flex; align-items: center; gap: 6px; }\r\n        #pth-tt-studio-wrapper .pth-sample-btn { background: #eff6ff; color: #1d4ed8; }\r\n        #pth-tt-studio-wrapper .pth-sample-btn:hover { background: #dbeafe; }\r\n        #pth-tt-studio-wrapper .pth-fw-btn { background: #e2e8f0; color: #0f172a; }\r\n        #pth-tt-studio-wrapper .pth-fw-btn:hover { background: #cbd5e1; }\r\n        #pth-tt-studio-wrapper .pth-clear-btn { background: #fef2f2; color: #991b1b; }\r\n        #pth-tt-studio-wrapper .pth-clear-btn:hover { background: #fee2e2; }\r\n\r\n        #pth-tt-studio-wrapper .pth-meta-bar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; padding: 8px 24px 0; }\r\n        #pth-tt-studio-wrapper .pth-version-badge { background: #eff6ff; color: #1d4ed8; font-size: 0.72rem; font-weight: 800; padding: 4px 10px; border-radius: 20px; letter-spacing: 0.4px; }\r\n        #pth-tt-studio-wrapper .pth-status-offline { background: #ecfdf5; color: #047857; font-size: 0.72rem; font-weight: 800; padding: 4px 10px; border-radius: 20px; }\r\n\r\n        #pth-tt-studio-wrapper .pth-tabbar { display: flex; gap: 4px; flex-wrap: wrap; padding: 16px 24px 0; border-bottom: 2px solid #e2e8f0; }\r\n        #pth-tt-studio-wrapper .pth-tab-btn { background: transparent; border: none; border-bottom: 3px solid transparent; margin-bottom: -2px; padding: 10px 15px; font-size: 0.88rem; font-weight: 700; color: #334155; cursor: pointer; font-family: inherit; border-radius: 6px 6px 0 0; }\r\n        #pth-tt-studio-wrapper .pth-tab-btn:hover { background: #f1f5f9; color: #0f172a; }\r\n        #pth-tt-studio-wrapper .pth-tab-btn.active { color: #1d4ed8; border-bottom-color: #2563eb; background: #eff6ff; }\r\n\r\n        #pth-tt-studio-wrapper .pth-grid { display: grid; grid-template-columns: 1.8fr 1fr; }\r\n        #pth-tt-studio-wrapper .pth-main { padding: 24px; border-right: 1px solid #e2e8f0; }\r\n        #pth-tt-studio-wrapper .pth-side { padding: 24px; background: #f8fafc; }\r\n        #pth-tt-studio-wrapper .pth-grid.full-width { grid-template-columns: 1fr; }\r\n        #pth-tt-studio-wrapper .pth-grid.full-width .pth-side { display: none; }\r\n        #pth-tt-studio-wrapper .pth-grid.full-width .pth-main { border-right: none; }\r\n\r\n        #pth-tt-studio-wrapper .pth-panel { display: none; }\r\n        #pth-tt-studio-wrapper .pth-panel.active { display: block; }\r\n        #pth-tt-studio-wrapper .pth-panel-intro { font-size: 0.9rem; color: #334155; line-height: 1.6; margin: 0 0 18px; font-weight: 500; }\r\n\r\n        #pth-tt-studio-wrapper .pth-field { margin-bottom: 16px; }\r\n        #pth-tt-studio-wrapper .pth-field > label { display: block; font-size: 0.9rem; font-weight: 700; margin-bottom: 8px; color: #334155; }\r\n        #pth-tt-studio-wrapper .pth-hint { font-size: 0.8rem; color: #334155; font-style: italic; margin: 0 0 6px; }\r\n        #pth-tt-studio-wrapper .pth-inp { width: 100%; padding: 12px 14px; border: 2px solid #cbd5e1; border-radius: 8px; font-family: 'Courier New', monospace; font-size: 1rem; font-weight: 700; color: #1d4ed8; background: #f8fafc; }\r\n        #pth-tt-studio-wrapper .pth-inp.small { font-size: 0.9rem; padding: 9px 12px; color: #0f172a; font-weight: 600; }\r\n        #pth-tt-studio-wrapper .pth-inp:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,0.12); }\r\n        #pth-tt-studio-wrapper .pth-row { display: flex; gap: 12px; flex-wrap: wrap; }\r\n        #pth-tt-studio-wrapper .pth-row .pth-field { flex: 1 1 180px; }\r\n\r\n        #pth-tt-studio-wrapper .pth-keyboard { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; background: #f8fafc; padding: 10px; border-radius: 8px; border: 1px solid #e2e8f0; }\r\n        #pth-tt-studio-wrapper .pth-key { padding: 6px 12px; background: #ffffff; border: 1px solid #cbd5e1; border-radius: 6px; cursor: pointer; font-weight: 700; font-family: monospace; font-size: 0.85rem; color: #334155; }\r\n        #pth-tt-studio-wrapper .pth-key:hover { background: #e2e8f0; }\r\n\r\n        #pth-tt-studio-wrapper .pth-check { display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; font-weight: 600; color: #334155; margin-right: 16px; cursor: pointer; }\r\n        #pth-tt-studio-wrapper .pth-action-btn { background: #2563eb; color: #ffffff; border: none; padding: 11px 20px; font-size: 0.9rem; font-weight: 700; border-radius: 8px; cursor: pointer; font-family: inherit; }\r\n        #pth-tt-studio-wrapper .pth-action-btn:hover { background: #1d4ed8; }\r\n        #pth-tt-studio-wrapper .pth-mini-btn { background: #ffffff; color: #0f172a; border: 1px solid #cbd5e1; padding: 7px 13px; font-size: 0.8rem; font-weight: 700; border-radius: 6px; cursor: pointer; font-family: inherit; }\r\n        #pth-tt-studio-wrapper .pth-mini-btn:hover { background: #f1f5f9; }\r\n        #pth-tt-studio-wrapper .pth-btn-row { display: flex; gap: 8px; flex-wrap: wrap; }\r\n\r\n        #pth-tt-studio-wrapper .pth-formula-box { font-family: monospace; background: #f8fafc; padding: 13px 15px; border-radius: 8px; border-left: 4px solid #2563eb; font-size: 1rem; font-weight: 700; color: #0f172a; margin: 18px 0 14px; word-break: break-word; min-height: 46px; }\r\n        #pth-tt-studio-wrapper .pth-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px,1fr)); gap: 12px; margin-bottom: 16px; }\r\n        #pth-tt-studio-wrapper .pth-stat-card { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 14px; text-align: center; }\r\n        #pth-tt-studio-wrapper .pth-stat-val { font-size: 1.6rem; font-weight: 800; color: #1d4ed8; }\r\n        #pth-tt-studio-wrapper .pth-stat-val.red { color: #991b1b; }\r\n        #pth-tt-studio-wrapper .pth-stat-lbl { font-size: 0.76rem; color: #334155; font-weight: 700; text-transform: uppercase; letter-spacing: 0.3px; }\r\n\r\n        #pth-tt-studio-wrapper .pth-table-wrap { overflow-x: auto; border: 1px solid #e2e8f0; border-radius: 8px; min-height: 60px; }\r\n        #pth-tt-studio-wrapper table.pth-table { width: 100%; border-collapse: collapse; text-align: center; }\r\n        #pth-tt-studio-wrapper .pth-table th { background: #f1f5f9; color: #334155; font-weight: 800; padding: 11px 13px; border-bottom: 2px solid #cbd5e1; border-right: 1px solid #e2e8f0; font-family: monospace; font-size: 0.85rem; white-space: nowrap; }\r\n        #pth-tt-studio-wrapper .pth-table th.final { background: #eff6ff; color: #1d4ed8; }\r\n        #pth-tt-studio-wrapper .pth-table td { padding: 9px 13px; border-bottom: 1px solid #f1f5f9; border-right: 1px solid #f1f5f9; font-family: monospace; font-size: 0.92rem; color: #0f172a; }\r\n        #pth-tt-studio-wrapper .res-true { background: #dcfce7; color: #166534; font-weight: 800; }\r\n        #pth-tt-studio-wrapper .res-false { background: #fef2f2; color: #991b1b; font-weight: 600; }\r\n        #pth-tt-studio-wrapper .row-diff td { background: #fef9c3 !important; }\r\n\r\n        #pth-tt-studio-wrapper .pth-card { border: 1px solid #e2e8f0; border-radius: 10px; padding: 16px; margin-top: 18px; background: #ffffff; }\r\n        #pth-tt-studio-wrapper .pth-card-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }\r\n        #pth-tt-studio-wrapper .pth-card-title { font-size: 0.95rem; font-weight: 800; color: #0f172a; margin: 0; }\r\n        #pth-tt-studio-wrapper .pth-code-box { background: #0f172a; color: #7dd3fc; padding: 16px; border-radius: 8px; font-family: 'Courier New', monospace; font-size: 0.86rem; white-space: pre-wrap; overflow-x: auto; margin: 0; min-height: 60px; }\r\n\r\n        #pth-tt-studio-wrapper .pth-verdict { padding: 14px 18px; border-radius: 8px; font-weight: 800; font-size: 1rem; margin: 16px 0; display: flex; align-items: center; gap: 10px; }\r\n        #pth-tt-studio-wrapper .pth-verdict.ok { background: #059669; color: #ffffff; }\r\n        #pth-tt-studio-wrapper .pth-verdict.bad { background: #dc2626; color: #ffffff; }\r\n        #pth-tt-studio-wrapper .pth-verdict.neutral { background: #e2e8f0; color: #334155; }\r\n\r\n        #pth-tt-studio-wrapper .pth-finding { padding: 12px 14px; border-radius: 8px; font-size: 0.88rem; line-height: 1.55; margin-bottom: 10px; font-weight: 500; }\r\n        #pth-tt-studio-wrapper .pth-f-ok { background: #ecfdf5; color: #047857; border: 1px solid #a7f3d0; }\r\n        #pth-tt-studio-wrapper .pth-f-warn { background: #fefce8; color: #92400e; border: 1px solid #fde68a; }\r\n        #pth-tt-studio-wrapper .pth-f-info { background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe; }\r\n        #pth-tt-studio-wrapper .pth-f-crit { background: #fef2f2; color: #991b1b; border: 1px solid #fecaca; }\r\n        #pth-tt-studio-wrapper .pth-finding strong { font-weight: 800; }\r\n\r\n        #pth-tt-studio-wrapper .pth-canon { font-family: monospace; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 14px; font-size: 0.92rem; color: #0f172a; word-break: break-word; margin-bottom: 12px; min-height: 46px; font-weight: 600; }\r\n        #pth-tt-studio-wrapper .pth-canon-lbl { font-size: 0.78rem; font-weight: 800; color: #5b21b6; text-transform: uppercase; letter-spacing: 0.4px; margin-bottom: 5px; display: block; }\r\n\r\n        #pth-tt-studio-wrapper .pth-wave-wrap { overflow-x: auto; border: 1px solid #e2e8f0; border-radius: 8px; background: #ffffff; padding: 12px; min-height: 120px; }\r\n        #pth-tt-studio-wrapper .pth-error-txt { color: #991b1b; font-weight: 700; font-size: 0.9rem; }\r\n\r\n        #pth-tt-studio-wrapper .pth-side-title { font-size: 0.95rem; font-weight: 800; margin: 0 0 10px; color: #0f172a; }\r\n        #pth-tt-studio-wrapper .pth-side-title.mt { margin-top: 22px; }\r\n        #pth-tt-studio-wrapper .pth-tpl-tabs { display: flex; gap: 6px; margin-bottom: 10px; flex-wrap: wrap; }\r\n        #pth-tt-studio-wrapper .pth-tpl-tab { padding: 5px 11px; font-size: 0.78rem; border-radius: 20px; border: 1px solid #cbd5e1; background: #ffffff; cursor: pointer; font-weight: 700; color: #334155; font-family: inherit; }\r\n        #pth-tt-studio-wrapper .pth-tpl-tab.active { background: #2563eb; color: #ffffff; border-color: #2563eb; }\r\n        #pth-tt-studio-wrapper .pth-tpl-grid { display: flex; flex-wrap: wrap; gap: 6px; }\r\n        #pth-tt-studio-wrapper .pth-tpl-btn { background: #ffffff; border: 1px solid #cbd5e1; color: #0f172a; padding: 7px 11px; border-radius: 6px; font-size: 0.8rem; font-weight: 700; cursor: pointer; font-family: inherit; }\r\n        #pth-tt-studio-wrapper .pth-tpl-btn:hover { background: #eff6ff; border-color: #93c5fd; }\r\n\r\n        #pth-tt-studio-wrapper table.pth-cheat { width: 100%; border-collapse: collapse; }\r\n        #pth-tt-studio-wrapper .pth-cheat td { padding: 6px 0; border-bottom: 1px solid #e2e8f0; font-size: 0.8rem; color: #334155; font-weight: 500; }\r\n        #pth-tt-studio-wrapper .pth-code { background: #e2e8f0; color: #0f172a; padding: 2px 6px; border-radius: 4px; font-family: monospace; font-size: 0.8rem; font-weight: 700; }\r\n        #pth-tt-studio-wrapper .pth-note { background: #fffbeb; border: 1px solid #fde68a; padding: 12px; border-radius: 8px; font-size: 0.83rem; color: #92400e; line-height: 1.55; font-weight: 500; margin-top: 18px; }\r\n        #pth-tt-studio-wrapper .pth-related a { color: #1d4ed8; text-decoration: none; font-weight: 700; }\r\n        #pth-tt-studio-wrapper .pth-related a:hover { text-decoration: underline; }\r\n        #pth-tt-studio-wrapper .pth-related li { margin-bottom: 7px; font-size: 0.85rem; }\r\n\r\n        #pth-tt-studio-wrapper .pth-toast-wrap { position: fixed; bottom: 20px; right: 20px; z-index: 999999; display: flex; flex-direction: column; gap: 8px; }\r\n        #pth-tt-studio-wrapper .pth-toast { padding: 12px 18px; border-radius: 8px; color: #ffffff; font-size: 0.88rem; font-weight: 700; box-shadow: 0 8px 24px rgba(0,0,0,0.18); }\r\n        #pth-tt-studio-wrapper .pth-toast.success { background: #059669; }\r\n        #pth-tt-studio-wrapper .pth-toast.error { background: #dc2626; }\r\n        #pth-tt-studio-wrapper .pth-toast.info { background: #2563eb; }\r\n\r\n        @media (max-width: 900px) {\r\n            #pth-tt-studio-wrapper .pth-grid { grid-template-columns: 1fr; }\r\n            #pth-tt-studio-wrapper .pth-main { border-right: none; border-bottom: 1px solid #e2e8f0; }\r\n        }\r\n    <\/style>\r\n\r\n    <div class=\"pth-topbar\">\r\n        <h2 class=\"pth-title\">Truth Table Studio Pro<\/h2>\r\n        <div class=\"pth-toolbar\">\r\n            <button type=\"button\" class=\"pth-btn pth-sample-btn\" id=\"pth-tt-sample\">\ud83d\udca1 Load Sample<\/button>\r\n            <button type=\"button\" class=\"pth-btn pth-fw-btn\" id=\"pth-tt-fw\" aria-label=\"Toggle full width view\">\u26f6 Full Width<\/button>\r\n            <button type=\"button\" class=\"pth-btn pth-clear-btn\" id=\"pth-tt-clear\">\ud83d\uddd1\ufe0f Clear<\/button>\r\n        <\/div>\r\n    <\/div>\r\n    <div class=\"pth-meta-bar\">\r\n        <span class=\"pth-version-badge\">TRUTH TABLE STUDIO v4.0<\/span>\r\n        <span class=\"pth-status-offline\">\ud83d\udd12 100% Offline<\/span>\r\n    <\/div>\r\n\r\n    <div class=\"pth-tabbar\" role=\"tablist\">\r\n        <button type=\"button\" class=\"pth-tab-btn active\" data-tab=\"table\" role=\"tab\">\ud83c\udfaf Truth Table<\/button>\r\n        <button type=\"button\" class=\"pth-tab-btn\" data-tab=\"equiv\" role=\"tab\">\u2696\ufe0f Equivalence<\/button>\r\n        <button type=\"button\" class=\"pth-tab-btn\" data-tab=\"canon\" role=\"tab\">\u03a3 Canonical Forms<\/button>\r\n        <button type=\"button\" class=\"pth-tab-btn\" data-tab=\"wave\" role=\"tab\">\ud83d\udcca Timing Waveform<\/button>\r\n        <button type=\"button\" class=\"pth-tab-btn\" data-tab=\"analysis\" role=\"tab\">\ud83e\udde0 Logic Analysis<\/button>\r\n    <\/div>\r\n\r\n    <div class=\"pth-grid\" id=\"pth-tt-grid\">\r\n        <div class=\"pth-main\">\r\n\r\n            <!-- TAB 1: TRUTH TABLE -->\r\n            <div class=\"pth-panel active\" id=\"pth-panel-table\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">Enter a Boolean expression and every input combination is evaluated for you. Variables are detected automatically, and intermediate sub-expressions get their own columns.<\/p>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-tt-formula\">Boolean Expression<\/label>\r\n                    <p class=\"pth-hint\">\u2139\ufe0f Words (AND, OR, NOT, XOR, NAND, NOR, XNOR) or symbols (&amp;, |, !, ^, ', -&gt;) both work. Click \ud83d\udca1 Load Sample for an example.<\/p>\r\n                    <input type=\"text\" id=\"pth-tt-formula\" class=\"pth-inp\" aria-label=\"Boolean expression\" placeholder=\"e.g. (A AND B) OR (NOT C)\">\r\n                    <div class=\"pth-keyboard\" id=\"pth-tt-keyboard\"><\/div>\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                    <label style=\"margin-bottom:4px;\">Options<\/label>\r\n                    <label class=\"pth-check\"><input type=\"checkbox\" id=\"pth-tt-steps\" checked> Show intermediate steps<\/label>\r\n                    <label class=\"pth-check\"><input type=\"checkbox\" id=\"pth-tt-hl\" checked> Highlight true (1)<\/label>\r\n                <\/div>\r\n                <button type=\"button\" class=\"pth-action-btn\" id=\"pth-tt-run\">\ud83c\udfaf Generate Truth Table<\/button>\r\n\r\n                <div id=\"pth-tt-error\" class=\"pth-error-txt\" style=\"margin-top:12px;\" role=\"alert\"><\/div>\r\n                <div id=\"pth-tt-results\" style=\"display:none;\">\r\n                    <div class=\"pth-formula-box\" id=\"pth-tt-expanded\"><\/div>\r\n                    <div class=\"pth-stats\">\r\n                        <div class=\"pth-stat-card\"><div class=\"pth-stat-val\" id=\"pth-tt-true\">0<\/div><div class=\"pth-stat-lbl\">True (1) rows<\/div><\/div>\r\n                        <div class=\"pth-stat-card\"><div class=\"pth-stat-val red\" id=\"pth-tt-false\">0<\/div><div class=\"pth-stat-lbl\">False (0) rows<\/div><\/div>\r\n                        <div class=\"pth-stat-card\"><div class=\"pth-stat-val\" id=\"pth-tt-pct\">0%<\/div><div class=\"pth-stat-lbl\">True percentage<\/div><\/div>\r\n                    <\/div>\r\n                    <div class=\"pth-btn-row\" style=\"margin-bottom:12px;\">\r\n                        <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-tt-csv\">\u2b07\ufe0f Export CSV<\/button>\r\n                        <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-tt-print\">\ud83d\udda8\ufe0f Print Table<\/button>\r\n                    <\/div>\r\n                    <div class=\"pth-table-wrap\" id=\"pth-tt-render\"><\/div>\r\n\r\n                    <div class=\"pth-card\">\r\n                        <div class=\"pth-card-head\">\r\n                            <p class=\"pth-card-title\">\u2699\ufe0f Verilog HDL Export<\/p>\r\n                            <div class=\"pth-btn-row\">\r\n                                <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-tt-vcopy\">Copy<\/button>\r\n                                <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-tt-vdl\">Download .v<\/button>\r\n                                <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-tt-djs\">Simulate on DigitalJS \u2197<\/button>\r\n                            <\/div>\r\n                        <\/div>\r\n                        <div class=\"pth-row\">\r\n                            <div class=\"pth-field\"><label for=\"pth-tt-vmod\">Module name<\/label><input type=\"text\" id=\"pth-tt-vmod\" class=\"pth-inp small\" value=\"Logic_Circuit\" aria-label=\"Verilog module name\"><\/div>\r\n                            <div class=\"pth-field\"><label for=\"pth-tt-vout\">Output name<\/label><input type=\"text\" id=\"pth-tt-vout\" class=\"pth-inp small\" value=\"Y\" aria-label=\"Verilog output name\"><\/div>\r\n                        <\/div>\r\n                        <pre class=\"pth-code-box\" id=\"pth-tt-vcode\">Generate a table to see the Verilog module.<\/pre>\r\n                        <p class=\"pth-hint\" style=\"margin:8px 0 0;\">DigitalJS opens an external simulator in a new tab. Everything else on this page stays offline.<\/p>\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- TAB 2: EQUIVALENCE -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-equiv\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">Prove two expressions are the same &mdash; or find the exact row where they disagree. Ideal for checking De Morgan's laws and simplification homework.<\/p>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-eq-a\">Expression 1<\/label>\r\n                    <input type=\"text\" id=\"pth-eq-a\" class=\"pth-inp\" aria-label=\"First expression\" placeholder=\"e.g. NOT (A AND B)\">\r\n                <\/div>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-eq-b\">Expression 2<\/label>\r\n                    <input type=\"text\" id=\"pth-eq-b\" class=\"pth-inp\" aria-label=\"Second expression\" placeholder=\"e.g. (NOT A) OR (NOT B)\">\r\n                <\/div>\r\n                <button type=\"button\" class=\"pth-action-btn\" id=\"pth-eq-run\">\u2696\ufe0f Compare Expressions<\/button>\r\n                <div id=\"pth-eq-error\" class=\"pth-error-txt\" style=\"margin-top:12px;\" role=\"alert\"><\/div>\r\n                <div id=\"pth-eq-verdict\" style=\"display:none;\"><\/div>\r\n                <div class=\"pth-table-wrap\" id=\"pth-eq-render\" style=\"display:none;\"><\/div>\r\n            <\/div>\r\n\r\n            <!-- TAB 3: CANONICAL -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-canon\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">Read the minterms and maxterms straight off the truth table, then see the canonical sum-of-products and product-of-sums that follow from them.<\/p>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-cn-formula\">Boolean Expression<\/label>\r\n                    <input type=\"text\" id=\"pth-cn-formula\" class=\"pth-inp\" aria-label=\"Expression for canonical forms\" placeholder=\"e.g. (A AND B) OR (NOT C)\">\r\n                <\/div>\r\n                <button type=\"button\" class=\"pth-action-btn\" id=\"pth-cn-run\">\u03a3 Derive Canonical Forms<\/button>\r\n                <div id=\"pth-cn-error\" class=\"pth-error-txt\" style=\"margin-top:12px;\" role=\"alert\"><\/div>\r\n                <div id=\"pth-cn-out\" style=\"display:none; margin-top:18px;\">\r\n                    <span class=\"pth-canon-lbl\">Minterm list (F = 1)<\/span>\r\n                    <div class=\"pth-canon\" id=\"pth-cn-min\"><\/div>\r\n                    <span class=\"pth-canon-lbl\">Canonical SOP (sum of products)<\/span>\r\n                    <div class=\"pth-canon\" id=\"pth-cn-sop\"><\/div>\r\n                    <span class=\"pth-canon-lbl\">Maxterm list (F = 0)<\/span>\r\n                    <div class=\"pth-canon\" id=\"pth-cn-max\"><\/div>\r\n                    <span class=\"pth-canon-lbl\">Canonical POS (product of sums)<\/span>\r\n                    <div class=\"pth-canon\" id=\"pth-cn-pos\"><\/div>\r\n                    <div class=\"pth-finding pth-f-info\" style=\"margin-top:14px;\">\r\n                        <strong>These are canonical, not minimal.<\/strong> Every minterm appears in full. To reduce them to the smallest expression, take the minterm list to the <a href=\"https:\/\/schoolict.net\/tools\/advanced-k-map-solver\/\" style=\"color:#1d4ed8;font-weight:800;\">K-Map Solver<\/a> or the <a href=\"https:\/\/schoolict.net\/tools\/boolean-expression-simplifier\/\" style=\"color:#1d4ed8;font-weight:800;\">Boolean Expression Simplifier<\/a>.\r\n                    <\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n            <!-- TAB 4: WAVEFORM -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-wave\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">See the same truth table as a digital timing diagram. Each input counts up in binary while the output tracks along beneath, exactly as a logic analyser would show it.<\/p>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-wv-formula\">Boolean Expression<\/label>\r\n                    <p class=\"pth-hint\">\u2139\ufe0f Up to 5 variables (32 time steps) stay readable as a waveform.<\/p>\r\n                    <input type=\"text\" id=\"pth-wv-formula\" class=\"pth-inp\" aria-label=\"Expression for waveform\" placeholder=\"e.g. A XOR B\">\r\n                <\/div>\r\n                <button type=\"button\" class=\"pth-action-btn\" id=\"pth-wv-run\">\ud83d\udcca Draw Waveform<\/button>\r\n                <div id=\"pth-wv-error\" class=\"pth-error-txt\" style=\"margin-top:12px;\" role=\"alert\"><\/div>\r\n                <div class=\"pth-btn-row\" style=\"margin-top:14px;\">\r\n                    <button type=\"button\" class=\"pth-mini-btn\" id=\"pth-wv-svg\" style=\"display:none;\">\u2b07\ufe0f Download SVG<\/button>\r\n                <\/div>\r\n                <div class=\"pth-wave-wrap\" id=\"pth-wv-render\" style=\"margin-top:12px;\">Draw a waveform to see the signal diagram.<\/div>\r\n            <\/div>\r\n\r\n            <!-- TAB 5: ANALYSIS -->\r\n            <div class=\"pth-panel\" id=\"pth-panel-analysis\" role=\"tabpanel\">\r\n                <p class=\"pth-panel-intro\">Classify an expression and inspect what it really depends on: is it always true, never true, or does it actually use every variable you gave it?<\/p>\r\n                <div class=\"pth-field\">\r\n                    <label for=\"pth-an-formula\">Boolean Expression<\/label>\r\n                    <input type=\"text\" id=\"pth-an-formula\" class=\"pth-inp\" aria-label=\"Expression to analyse\" placeholder=\"e.g. A OR (B AND NOT B)\">\r\n                <\/div>\r\n                <button type=\"button\" class=\"pth-action-btn\" id=\"pth-an-run\">\ud83e\udde0 Analyse Expression<\/button>\r\n                <div id=\"pth-an-error\" class=\"pth-error-txt\" style=\"margin-top:12px;\" role=\"alert\"><\/div>\r\n                <div id=\"pth-an-out\" style=\"margin-top:18px;\">\r\n                    <div class=\"pth-finding pth-f-info\">Run an analysis to classify the expression and check for redundant variables.<\/div>\r\n                <\/div>\r\n            <\/div>\r\n\r\n        <\/div>\r\n\r\n        <div class=\"pth-side\">\r\n            <h3 class=\"pth-side-title\">\ud83d\udd04 Templates<\/h3>\r\n            <div class=\"pth-tpl-tabs\" id=\"pth-tpl-tabs\">\r\n                <button type=\"button\" class=\"pth-tpl-tab active\" data-lvl=\"basic\">Basic<\/button>\r\n                <button type=\"button\" class=\"pth-tpl-tab\" data-lvl=\"inter\">Intermediate<\/button>\r\n                <button type=\"button\" class=\"pth-tpl-tab\" data-lvl=\"adv\">Advanced<\/button>\r\n            <\/div>\r\n            <div class=\"pth-tpl-grid\" id=\"pth-tpl-grid\"><\/div>\r\n\r\n            <h3 class=\"pth-side-title mt\">Operators<\/h3>\r\n            <table class=\"pth-cheat\"><tbody id=\"pth-cheat-body\"><\/tbody><\/table>\r\n\r\n            <div class=\"pth-note\"><strong>\ud83d\udd12 Runs on your device.<\/strong> The expression parser is built in, with no <span class=\"pth-code\">eval<\/span> and no server calls. Nothing you type is uploaded.<\/div>\r\n\r\n            <h3 class=\"pth-side-title mt\">Related Tools<\/h3>\r\n            <ul class=\"pth-related\" style=\"list-style:none; padding:0; margin:0;\">\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/advanced-k-map-solver\/\">K-Map Solver<\/a><\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/boolean-expression-simplifier\/\">Boolean Simplifier<\/a><\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/universal-logic-gate-converter-pro\/\">Logic Gate Converter<\/a><\/li>\r\n                <li><a href=\"https:\/\/schoolict.net\/tools\/7400-series-ic-finder\/\">7400 Series IC Finder<\/a><\/li>\r\n            <\/ul>\r\n        <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"pth-toast-wrap\" id=\"pth-tt-toast-wrap\" aria-live=\"assertive\"><\/div>\r\n\r\n    <script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\n    (function () {\r\n        'use strict';\r\n        if (window.pthTruthTableApp) { return; }\r\n\r\n        var KEYWORDS = { 'NOT':1, 'AND':1, 'NAND':1, 'OR':1, 'NOR':1, 'XOR':1, 'XNOR':1, 'IMPLIES':1, 'IFF':1 };\r\n\r\n        window.pthTruthTableApp = {\r\n            initialized: false,\r\n            lastTable: null,\r\n            lastSvg: '',\r\n            verilogCode: '',\r\n\r\n            keys: ['AND','OR','NOT','XOR','NAND','NOR','XNOR','IMPLIES','(',')','A','B','C','D'],\r\n\r\n            templates: {\r\n                basic: [\r\n                    { n:'AND', f:'A AND B' }, { n:'OR', f:'A OR B' }, { n:'NOT', f:'NOT A' },\r\n                    { n:'XOR', f:'A XOR B' }, { n:'NAND', f:'A NAND B' }, { n:'NOR', f:'A NOR B' }\r\n                ],\r\n                inter: [\r\n                    { n:'Majority vote', f:'(A AND B) OR (A AND C) OR (B AND C)' },\r\n                    { n:'XOR chain', f:'A XOR B XOR C' },\r\n                    { n:'AND-OR-NOT', f:'(A AND B) OR (NOT C)' },\r\n                    { n:'Parity check', f:'A XOR B XOR C XOR D' },\r\n                    { n:'De Morgan', f:'NOT (A AND B)' }\r\n                ],\r\n                adv: [\r\n                    { n:'Full adder sum', f:'A XOR B XOR C' },\r\n                    { n:'Full adder carry', f:'(A AND B) OR (B AND C) OR (A AND C)' },\r\n                    { n:'2-to-1 MUX', f:'(A AND S) OR (B AND (NOT S))' },\r\n                    { n:'Implication', f:'A IMPLIES B' },\r\n                    { n:'Redundant var', f:'A OR (B AND NOT B)' }\r\n                ]\r\n            },\r\n\r\n            cheat: [\r\n                { c:'AND  &amp;  *', d:'Conjunction' },\r\n                { c:'OR  +  |', d:'Disjunction' },\r\n                { c:'NOT  !  ~  \\u2019', d:'Negation' },\r\n                { c:'XOR  ^', d:'Exclusive OR' },\r\n                { c:'XNOR', d:'Equivalence gate' },\r\n                { c:'NAND \/ NOR', d:'Universal gates' },\r\n                { c:'IMPLIES  -&gt;', d:'Implication' },\r\n                { c:'IFF  &lt;-&gt;', d:'Biconditional' }\r\n            ],\r\n\r\n            \/* ================= INIT ================= *\/\r\n            init: function () {\r\n                this.wrapper = document.getElementById('pth-tt-studio-wrapper');\r\n                if (!this.wrapper) { return; }\r\n                this.grid = document.getElementById('pth-tt-grid');\r\n                this.activeTab = 'table';\r\n                this.renderKeyboard();\r\n                this.renderCheat();\r\n                this.renderTemplates('basic');\r\n                this.attachEvents();\r\n                this.applyDeepLink();\r\n            },\r\n\r\n            applyDeepLink: function () {\r\n                try {\r\n                    var t = new URLSearchParams(window.location.search).get('tab');\r\n                    if (t) { this.switchTab(t); }\r\n                } catch (e) {}\r\n            },\r\n\r\n            renderKeyboard: function () {\r\n                var kb = document.getElementById('pth-tt-keyboard');\r\n                for (var i = 0; i < this.keys.length; i++) {\r\n                    var b = document.createElement('button');\r\n                    b.type = 'button';\r\n                    b.className = 'pth-key';\r\n                    b.textContent = this.keys[i];\r\n                    b.setAttribute('data-key', this.keys[i]);\r\n                    kb.appendChild(b);\r\n                }\r\n            },\r\n\r\n            renderCheat: function () {\r\n                var body = document.getElementById('pth-cheat-body');\r\n                for (var i = 0; i < this.cheat.length; i++) {\r\n                    var tr = document.createElement('tr');\r\n                    var td1 = document.createElement('td');\r\n                    var sp = document.createElement('span');\r\n                    sp.className = 'pth-code';\r\n                    sp.innerHTML = this.cheat[i].c;\r\n                    td1.appendChild(sp);\r\n                    var td2 = document.createElement('td');\r\n                    td2.textContent = this.cheat[i].d;\r\n                    tr.appendChild(td1); tr.appendChild(td2);\r\n                    body.appendChild(tr);\r\n                }\r\n            },\r\n\r\n            renderTemplates: function (lvl) {\r\n                var grid = document.getElementById('pth-tpl-grid');\r\n                var list = this.templates[lvl] || [];\r\n                grid.innerHTML = '';\r\n                for (var i = 0; i < list.length; i++) {\r\n                    var b = document.createElement('button');\r\n                    b.type = 'button';\r\n                    b.className = 'pth-tpl-btn';\r\n                    b.textContent = list[i].n;\r\n                    b.setAttribute('data-f', list[i].f);\r\n                    grid.appendChild(b);\r\n                }\r\n                var tabs = document.getElementById('pth-tpl-tabs').querySelectorAll('.pth-tpl-tab');\r\n                for (var j = 0; j < tabs.length; j++) {\r\n                    if (tabs[j].getAttribute('data-lvl') === lvl) { tabs[j].classList.add('active'); }\r\n                    else { tabs[j].classList.remove('active'); }\r\n                }\r\n            },\r\n\r\n            attachEvents: function () {\r\n                var self = this, i;\r\n                var w = this.wrapper;\r\n\r\n                var tabs = w.querySelectorAll('.pth-tab-btn');\r\n                for (i = 0; i < tabs.length; i++) {\r\n                    tabs[i].addEventListener('click', function () { self.switchTab(this.getAttribute('data-tab')); });\r\n                }\r\n\r\n                document.getElementById('pth-tt-sample').addEventListener('click', function () { self.loadSample(); });\r\n                document.getElementById('pth-tt-clear').addEventListener('click', function () { self.clearActive(); });\r\n                document.getElementById('pth-tt-fw').addEventListener('click', function () { self.toggleWidth(); });\r\n\r\n                document.getElementById('pth-tt-keyboard').addEventListener('click', function (e) {\r\n                    var k = e.target.getAttribute && e.target.getAttribute('data-key');\r\n                    if (k) { self.insertKey(k); }\r\n                });\r\n\r\n                document.getElementById('pth-tpl-tabs').addEventListener('click', function (e) {\r\n                    var lvl = e.target.getAttribute && e.target.getAttribute('data-lvl');\r\n                    if (lvl) { self.renderTemplates(lvl); }\r\n                });\r\n                document.getElementById('pth-tpl-grid').addEventListener('click', function (e) {\r\n                    var f = e.target.getAttribute && e.target.getAttribute('data-f');\r\n                    if (f) { self.applyTemplate(f); }\r\n                });\r\n\r\n                document.getElementById('pth-tt-run').addEventListener('click', function () { self.runTable(); });\r\n                document.getElementById('pth-tt-csv').addEventListener('click', function () { self.exportCsv(); });\r\n                document.getElementById('pth-tt-print').addEventListener('click', function () { self.printTable(); });\r\n                document.getElementById('pth-tt-vcopy').addEventListener('click', function () { self.copyText(self.verilogCode); });\r\n                document.getElementById('pth-tt-vdl').addEventListener('click', function () { self.downloadVerilog(); });\r\n                document.getElementById('pth-tt-djs').addEventListener('click', function () { self.openDigitalJs(); });\r\n                document.getElementById('pth-tt-vmod').addEventListener('input', function () { self.refreshVerilog(); });\r\n                document.getElementById('pth-tt-vout').addEventListener('input', function () { self.refreshVerilog(); });\r\n\r\n                document.getElementById('pth-eq-run').addEventListener('click', function () { self.runEquiv(); });\r\n                document.getElementById('pth-cn-run').addEventListener('click', function () { self.runCanon(); });\r\n                document.getElementById('pth-wv-run').addEventListener('click', function () { self.runWave(); });\r\n                document.getElementById('pth-wv-svg').addEventListener('click', function () { self.downloadSvg(); });\r\n                document.getElementById('pth-an-run').addEventListener('click', function () { self.runAnalysis(); });\r\n            },\r\n\r\n            switchTab: function (name) {\r\n                var valid = { table:1, equiv:1, canon:1, wave:1, analysis:1 };\r\n                if (!valid[name]) { return; }\r\n                this.activeTab = name;\r\n                var w = this.wrapper, i;\r\n                var tabs = w.querySelectorAll('.pth-tab-btn');\r\n                for (i = 0; i < tabs.length; i++) {\r\n                    if (tabs[i].getAttribute('data-tab') === name) { tabs[i].classList.add('active'); }\r\n                    else { tabs[i].classList.remove('active'); }\r\n                }\r\n                var panels = w.querySelectorAll('.pth-panel');\r\n                for (i = 0; i < panels.length; i++) {\r\n                    if (panels[i].id === 'pth-panel-' + name) { panels[i].classList.add('active'); }\r\n                    else { panels[i].classList.remove('active'); }\r\n                }\r\n            },\r\n\r\n            toggleWidth: function () {\r\n                this.grid.classList.toggle('full-width');\r\n                var b = document.getElementById('pth-tt-fw');\r\n                b.textContent = this.grid.classList.contains('full-width') ? '\\u25E7 Split View' : '\\u26F6 Full Width';\r\n            },\r\n\r\n            insertKey: function (k) {\r\n                var input = document.getElementById('pth-tt-formula');\r\n                var pad = (k.length > 1 && k !== '(' && k !== ')') ? ' ' + k + ' ' : k;\r\n                input.value += pad;\r\n                input.focus();\r\n            },\r\n\r\n            applyTemplate: function (f) {\r\n                var map = { table:'pth-tt-formula', canon:'pth-cn-formula', wave:'pth-wv-formula', analysis:'pth-an-formula' };\r\n                if (this.activeTab === 'equiv') {\r\n                    document.getElementById('pth-eq-a').value = f;\r\n                    this.showToast('Loaded into Expression 1', 'success');\r\n                    return;\r\n                }\r\n                var id = map[this.activeTab] || 'pth-tt-formula';\r\n                document.getElementById(id).value = f;\r\n                this.showToast('Template loaded', 'success');\r\n            },\r\n\r\n            loadSample: function () {\r\n                var t = this.activeTab;\r\n                if (t === 'table') { document.getElementById('pth-tt-formula').value = '(A AND B) OR (NOT C)'; this.runTable(); }\r\n                else if (t === 'equiv') {\r\n                    document.getElementById('pth-eq-a').value = 'NOT (A AND B)';\r\n                    document.getElementById('pth-eq-b').value = '(NOT A) OR (NOT B)';\r\n                    this.runEquiv();\r\n                }\r\n                else if (t === 'canon') { document.getElementById('pth-cn-formula').value = '(A AND B) OR (NOT C)'; this.runCanon(); }\r\n                else if (t === 'wave') { document.getElementById('pth-wv-formula').value = 'A XOR B'; this.runWave(); }\r\n                else if (t === 'analysis') { document.getElementById('pth-an-formula').value = 'A OR (B AND NOT B)'; this.runAnalysis(); }\r\n                this.showToast('Sample loaded', 'success');\r\n            },\r\n\r\n            clearActive: function () {\r\n                var t = this.activeTab;\r\n                if (t === 'table') {\r\n                    document.getElementById('pth-tt-formula').value = '';\r\n                    document.getElementById('pth-tt-results').style.display = 'none';\r\n                    document.getElementById('pth-tt-error').textContent = '';\r\n                    this.lastTable = null;\r\n                } else if (t === 'equiv') {\r\n                    document.getElementById('pth-eq-a').value = '';\r\n                    document.getElementById('pth-eq-b').value = '';\r\n                    document.getElementById('pth-eq-verdict').style.display = 'none';\r\n                    document.getElementById('pth-eq-render').style.display = 'none';\r\n                    document.getElementById('pth-eq-error').textContent = '';\r\n                } else if (t === 'canon') {\r\n                    document.getElementById('pth-cn-formula').value = '';\r\n                    document.getElementById('pth-cn-out').style.display = 'none';\r\n                    document.getElementById('pth-cn-error').textContent = '';\r\n                } else if (t === 'wave') {\r\n                    document.getElementById('pth-wv-formula').value = '';\r\n                    document.getElementById('pth-wv-render').textContent = 'Draw a waveform to see the signal diagram.';\r\n                    document.getElementById('pth-wv-svg').style.display = 'none';\r\n                    document.getElementById('pth-wv-error').textContent = '';\r\n                } else if (t === 'analysis') {\r\n                    document.getElementById('pth-an-formula').value = '';\r\n                    document.getElementById('pth-an-out').innerHTML = '<div class=\"pth-finding pth-f-info\">Run an analysis to classify the expression and check for redundant variables.<\/div>';\r\n                    document.getElementById('pth-an-error').textContent = '';\r\n                }\r\n                this.showToast('Cleared', 'info');\r\n            },\r\n\r\n            \/* ================= PARSER (no eval) ================= *\/\r\n            tokenize: function (src) {\r\n                var toks = [], i = 0, s = src;\r\n                while (i < s.length) {\r\n                    var c = s.charAt(i);\r\n                    if (\/\\s\/.test(c)) { i++; continue; }\r\n                    if (s.substr(i,3) === '<->' || s.substr(i,3) === '<=>') { toks.push({t:'op',v:'IFF'}); i += 3; continue; }\r\n                    if (s.substr(i,2) === '->' || s.substr(i,2) === '=>') { toks.push({t:'op',v:'IMPLIES'}); i += 2; continue; }\r\n                    if (s.substr(i,2) === '&&') { toks.push({t:'op',v:'AND'}); i += 2; continue; }\r\n                    if (s.substr(i,2) === '||') { toks.push({t:'op',v:'OR'}); i += 2; continue; }\r\n                    if (c === '&' || c === '*' || c === '\\u00B7') { toks.push({t:'op',v:'AND'}); i++; continue; }\r\n                    if (c === '+' || c === '|') { toks.push({t:'op',v:'OR'}); i++; continue; }\r\n                    if (c === '^' || c === '\\u2295') { toks.push({t:'op',v:'XOR'}); i++; continue; }\r\n                    if (c === '!' || c === '~') { toks.push({t:'not'}); i++; continue; }\r\n                    if (c === '\\u0027' || c === '\\u2019') { toks.push({t:'post'}); i++; continue; }\r\n                    if (c === '(') { toks.push({t:'lp'}); i++; continue; }\r\n                    if (c === ')') { toks.push({t:'rp'}); i++; continue; }\r\n                    if (c === '0' || c === '1') { toks.push({t:'const', v: c === '1' ? 1 : 0}); i++; continue; }\r\n                    if (\/[A-Za-z_]\/.test(c)) {\r\n                        var j = i;\r\n                        while (j < s.length && \/[A-Za-z0-9_]\/.test(s.charAt(j))) { j++; }\r\n                        var up = s.substring(i, j).toUpperCase();\r\n                        if (KEYWORDS[up]) {\r\n                            if (up === 'NOT') { toks.push({t:'not'}); } else { toks.push({t:'op', v:up}); }\r\n                        } else { toks.push({t:'var', v:up}); }\r\n                        i = j; continue;\r\n                    }\r\n                    throw new Error('Unexpected character \"' + c + '\"');\r\n                }\r\n                if (toks.length === 0) { throw new Error('Expression is empty'); }\r\n                return toks;\r\n            },\r\n\r\n            parse: function (toks) {\r\n                var pos = 0;\r\n                function peek() { return toks[pos]; }\r\n                function isOp(n) { var t = peek(); return t && t.t === 'op' && t.v === n; }\r\n                function primary() {\r\n                    var t = peek(), node;\r\n                    if (!t) { throw new Error('Unexpected end of expression'); }\r\n                    if (t.t === 'not') { pos++; node = { t:'not', a: primary() }; }\r\n                    else if (t.t === 'lp') {\r\n                        pos++; node = iff();\r\n                        if (!peek() || peek().t !== 'rp') { throw new Error('Missing closing parenthesis'); }\r\n                        pos++;\r\n                    }\r\n                    else if (t.t === 'var') { pos++; node = { t:'var', v:t.v }; }\r\n                    else if (t.t === 'const') { pos++; node = { t:'const', v:t.v }; }\r\n                    else { throw new Error('Unexpected token in expression'); }\r\n                    while (peek() && peek().t === 'post') { pos++; node = { t:'not', a:node }; }\r\n                    return node;\r\n                }\r\n                function andLvl() {\r\n                    var n = primary();\r\n                    while (isOp('AND') || isOp('NAND')) { var o = peek().v; pos++; n = { t:'bin', op:o, a:n, b:primary() }; }\r\n                    return n;\r\n                }\r\n                function xorLvl() {\r\n                    var n = andLvl();\r\n                    while (isOp('XOR') || isOp('XNOR')) { var o = peek().v; pos++; n = { t:'bin', op:o, a:n, b:andLvl() }; }\r\n                    return n;\r\n                }\r\n                function orLvl() {\r\n                    var n = xorLvl();\r\n                    while (isOp('OR') || isOp('NOR')) { var o = peek().v; pos++; n = { t:'bin', op:o, a:n, b:xorLvl() }; }\r\n                    return n;\r\n                }\r\n                function implies() {\r\n                    var n = orLvl();\r\n                    if (isOp('IMPLIES')) { pos++; n = { t:'bin', op:'IMPLIES', a:n, b:implies() }; }\r\n                    return n;\r\n                }\r\n                function iff() {\r\n                    var n = implies();\r\n                    while (isOp('IFF')) { pos++; n = { t:'bin', op:'IFF', a:n, b:implies() }; }\r\n                    return n;\r\n                }\r\n                var ast = iff();\r\n                if (pos < toks.length) { throw new Error('Unexpected trailing token'); }\r\n                return ast;\r\n            },\r\n\r\n            evalNode: function (n, vals) {\r\n                if (n.t === 'const') { return n.v; }\r\n                if (n.t === 'var') { return vals[n.v]; }\r\n                if (n.t === 'not') { return this.evalNode(n.a, vals) ? 0 : 1; }\r\n                var a = this.evalNode(n.a, vals), b = this.evalNode(n.b, vals);\r\n                if (n.op === 'AND') { return (a && b) ? 1 : 0; }\r\n                if (n.op === 'NAND') { return (a && b) ? 0 : 1; }\r\n                if (n.op === 'OR') { return (a || b) ? 1 : 0; }\r\n                if (n.op === 'NOR') { return (a || b) ? 0 : 1; }\r\n                if (n.op === 'XOR') { return (a !== b) ? 1 : 0; }\r\n                if (n.op === 'XNOR') { return (a === b) ? 1 : 0; }\r\n                if (n.op === 'IMPLIES') { return (a && !b) ? 0 : 1; }\r\n                if (n.op === 'IFF') { return (a === b) ? 1 : 0; }\r\n                throw new Error('Unknown operator');\r\n            },\r\n\r\n            nodeStr: function (n) {\r\n                if (n.t === 'const') { return String(n.v); }\r\n                if (n.t === 'var') { return n.v; }\r\n                if (n.t === 'not') { return 'NOT ' + (n.a.t === 'bin' ? '(' + this.nodeStr(n.a) + ')' : this.nodeStr(n.a)); }\r\n                return this.nodeStr(n.a) + ' ' + n.op + ' ' + this.nodeStr(n.b);\r\n            },\r\n\r\n            collectVars: function (toks) {\r\n                var seen = {}, out = [];\r\n                for (var i = 0; i < toks.length; i++) {\r\n                    if (toks[i].t === 'var' && !seen[toks[i].v]) { seen[toks[i].v] = 1; out.push(toks[i].v); }\r\n                }\r\n                out.sort();\r\n                return out;\r\n            },\r\n\r\n            subExpressions: function (root) {\r\n                var self = this, list = [], seen = {};\r\n                function walk(n) {\r\n                    if (!n || n.t === 'var' || n.t === 'const') { return; }\r\n                    if (n.t === 'not') { walk(n.a); }\r\n                    else { walk(n.a); walk(n.b); }\r\n                    if (n !== root) {\r\n                        var s = self.nodeStr(n);\r\n                        if (!seen[s] && !(n.t === 'not' && n.a.t === 'var')) { seen[s] = 1; list.push({ s:s, node:n }); }\r\n                        else if (!seen[s] && n.t === 'not') { seen[s] = 1; list.push({ s:s, node:n }); }\r\n                    }\r\n                }\r\n                walk(root);\r\n                return list.slice(0, 6);\r\n            },\r\n\r\n            \/* Build full table object from an expression string *\/\r\n            buildTable: function (expr) {\r\n                var toks = this.tokenize(expr);\r\n                var ast = this.parse(toks);\r\n                var vars = this.collectVars(toks);\r\n                if (vars.length === 0) { throw new Error('No variables found in the expression'); }\r\n                if (vars.length > 8) { throw new Error('Maximum 8 variables (256 rows) supported'); }\r\n                var rows = [], n = vars.length, total = Math.pow(2, n), i, k;\r\n                for (i = 0; i < total; i++) {\r\n                    var vals = {};\r\n                    for (k = 0; k < n; k++) { vals[vars[k]] = (i >> (n - k - 1)) & 1; }\r\n                    rows.push({ vals: vals, out: this.evalNode(ast, vals) });\r\n                }\r\n                return { expr: expr, ast: ast, vars: vars, rows: rows };\r\n            },\r\n\r\n            escapeHtml: function (s) {\r\n                return String(s).replace(\/&\/g, '&amp;').replace(\/<\/g, '&lt;').replace(\/>\/g, '&gt;').replace(\/\"\/g, '&quot;');\r\n            },\r\n\r\n            showError: function (id, msg) {\r\n                document.getElementById(id).textContent = '\\u26A0\\uFE0F ' + msg;\r\n            },\r\n            clearError: function (id) { document.getElementById(id).textContent = ''; },\r\n\r\n            \/* ================= TAB 1 ================= *\/\r\n            runTable: function () {\r\n                var expr = document.getElementById('pth-tt-formula').value.trim();\r\n                var results = document.getElementById('pth-tt-results');\r\n                this.clearError('pth-tt-error');\r\n                if (!expr) { results.style.display = 'none'; this.showError('pth-tt-error', 'Enter a Boolean expression first.'); return; }\r\n\r\n                var data;\r\n                try { data = this.buildTable(expr); }\r\n                catch (e) { results.style.display = 'none'; this.showError('pth-tt-error', e.message); this.showToast('Syntax error', 'error'); return; }\r\n\r\n                this.lastTable = data;\r\n                var showSteps = document.getElementById('pth-tt-steps').checked;\r\n                var hl = document.getElementById('pth-tt-hl').checked;\r\n                var subs = showSteps ? this.subExpressions(data.ast) : [];\r\n\r\n                var html = '<table class=\"pth-table\"><thead><tr>', i, j;\r\n                for (i = 0; i < data.vars.length; i++) { html += '<th>' + this.escapeHtml(data.vars[i]) + '<\/th>'; }\r\n                for (i = 0; i < subs.length; i++) { html += '<th>' + this.escapeHtml(subs[i].s) + '<\/th>'; }\r\n                html += '<th class=\"final\">' + this.escapeHtml(this.nodeStr(data.ast)) + '<\/th><\/tr><\/thead><tbody>';\r\n\r\n                var trueCnt = 0;\r\n                for (i = 0; i < data.rows.length; i++) {\r\n                    var row = data.rows[i];\r\n                    html += '<tr>';\r\n                    for (j = 0; j < data.vars.length; j++) {\r\n                        var vv = row.vals[data.vars[j]];\r\n                        html += '<td class=\"' + (hl && vv ? 'res-true' : '') + '\">' + vv + '<\/td>';\r\n                    }\r\n                    for (j = 0; j < subs.length; j++) {\r\n                        var sv = this.evalNode(subs[j].node, row.vals);\r\n                        html += '<td class=\"' + (hl && sv ? 'res-true' : '') + '\">' + sv + '<\/td>';\r\n                    }\r\n                    if (row.out) { trueCnt++; }\r\n                    html += '<td class=\"' + (row.out ? 'res-true' : 'res-false') + '\">' + row.out + '<\/td><\/tr>';\r\n                }\r\n                html += '<\/tbody><\/table>';\r\n\r\n                document.getElementById('pth-tt-render').innerHTML = html;\r\n                document.getElementById('pth-tt-expanded').textContent = 'Y = ' + this.nodeStr(data.ast);\r\n                document.getElementById('pth-tt-true').textContent = trueCnt;\r\n                document.getElementById('pth-tt-false').textContent = data.rows.length - trueCnt;\r\n                document.getElementById('pth-tt-pct').textContent = Math.round((trueCnt \/ data.rows.length) * 100) + '%';\r\n                results.style.display = 'block';\r\n                this.refreshVerilog();\r\n                this.showToast('Table generated', 'success');\r\n            },\r\n\r\n            toVerilogExpr: function (n) {\r\n                if (n.t === 'const') { return String(n.v); }\r\n                if (n.t === 'var') { return n.v; }\r\n                if (n.t === 'not') { return '~(' + this.toVerilogExpr(n.a) + ')'; }\r\n                var a = '(' + this.toVerilogExpr(n.a) + ')', b = '(' + this.toVerilogExpr(n.b) + ')';\r\n                if (n.op === 'AND') { return a + ' & ' + b; }\r\n                if (n.op === 'NAND') { return '~(' + a + ' & ' + b + ')'; }\r\n                if (n.op === 'OR') { return a + ' | ' + b; }\r\n                if (n.op === 'NOR') { return '~(' + a + ' | ' + b + ')'; }\r\n                if (n.op === 'XOR') { return a + ' ^ ' + b; }\r\n                if (n.op === 'XNOR') { return '~(' + a + ' ^ ' + b + ')'; }\r\n                if (n.op === 'IMPLIES') { return '~' + a + ' | ' + b; }\r\n                if (n.op === 'IFF') { return '~(' + a + ' ^ ' + b + ')'; }\r\n                return '';\r\n            },\r\n\r\n            refreshVerilog: function () {\r\n                if (!this.lastTable) { return; }\r\n                var mod = document.getElementById('pth-tt-vmod').value.replace(\/[^A-Za-z0-9_]\/g, '_') || 'Logic_Circuit';\r\n                var out = document.getElementById('pth-tt-vout').value.replace(\/[^A-Za-z0-9_]\/g, '_') || 'Y';\r\n                var vars = this.lastTable.vars;\r\n                var code = 'module ' + mod + '(\\n';\r\n                for (var i = 0; i < vars.length; i++) { code += '    input  ' + vars[i] + ',\\n'; }\r\n                code += '    output ' + out + '\\n);\\n\\n';\r\n                code += '    \/\/ Generated by Prime Tool Hub\\n';\r\n                code += '    assign ' + out + ' = ' + this.toVerilogExpr(this.lastTable.ast) + ';\\n\\nendmodule';\r\n                this.verilogCode = code;\r\n                document.getElementById('pth-tt-vcode').textContent = code;\r\n            },\r\n\r\n            downloadVerilog: function () {\r\n                if (!this.verilogCode) { this.showToast('Generate a table first', 'info'); return; }\r\n                var mod = document.getElementById('pth-tt-vmod').value.replace(\/[^A-Za-z0-9_]\/g, '_') || 'Logic_Circuit';\r\n                this.downloadBlob(this.verilogCode, mod + '.v', 'text\/plain');\r\n            },\r\n\r\n            openDigitalJs: function () {\r\n                if (!this.verilogCode) { this.showToast('Generate a table first', 'info'); return; }\r\n                window.open('https:\/\/digitaljs.tilk.eu\/?code=' + encodeURIComponent(this.verilogCode), '_blank', 'noopener');\r\n            },\r\n\r\n            exportCsv: function () {\r\n                if (!this.lastTable) { this.showToast('Generate a table first', 'info'); return; }\r\n                var d = this.lastTable, i, j;\r\n                var csv = '\"Expression: ' + d.expr.replace(\/\"\/g, '\"\"') + '\"\\n\\n';\r\n                csv += d.vars.join(',') + ',Result\\n';\r\n                for (i = 0; i < d.rows.length; i++) {\r\n                    var cells = [];\r\n                    for (j = 0; j < d.vars.length; j++) { cells.push(d.rows[i].vals[d.vars[j]]); }\r\n                    cells.push(d.rows[i].out);\r\n                    csv += cells.join(',') + '\\n';\r\n                }\r\n                this.downloadBlob(csv, 'truth_table.csv', 'text\/csv');\r\n                this.showToast('CSV exported', 'success');\r\n            },\r\n\r\n            downloadBlob: function (content, filename, mime) {\r\n                var blob = new Blob([content], { type: mime });\r\n                var url = URL.createObjectURL(blob);\r\n                var a = document.createElement('a');\r\n                a.href = url; a.download = filename;\r\n                document.body.appendChild(a); a.click();\r\n                document.body.removeChild(a);\r\n                setTimeout(function () { URL.revokeObjectURL(url); }, 1000);\r\n            },\r\n\r\n            printTable: function () {\r\n                if (!this.lastTable) { this.showToast('Generate a table first', 'info'); return; }\r\n                var tableHtml = document.getElementById('pth-tt-render').innerHTML;\r\n                var title = 'Truth Table \\u2014 ' + this.escapeHtml(this.lastTable.expr);\r\n                var win = window.open('', '', 'height=650,width=900');\r\n                if (!win) { this.showToast('Popup blocked by browser', 'error'); return; }\r\n                var css = 'body{font-family:sans-serif;color:#0f172a;padding:24px;}'\r\n                    + 'table{width:100%;border-collapse:collapse;text-align:center;}'\r\n                    + 'th,td{border:1px solid #cbd5e1;padding:9px;font-family:monospace;}'\r\n                    + 'th{background:#f1f5f9;}'\r\n                    + '.res-true{background:#dcfce7;color:#166534;font-weight:bold;}'\r\n                    + '.res-false{background:#fef2f2;color:#991b1b;}'\r\n                    + 'h2{text-align:center;}'\r\n                    + '@media print{ body{padding:0;} }'\r\n                    + 'table,th,td{ print-color-adjust:exact; -webkit-print-color-adjust:exact; }';\r\n                var doc = '<' + 'html><' + 'head><title>' + title + '<' + '\/title>';\r\n                doc += '<' + 'style>' + css + '<' + '\/style><' + '\/head>';\r\n                doc += '<' + 'body><h2>' + title + '<\/h2>' + tableHtml;\r\n                doc += '<p style=\"text-align:center;margin-top:26px;font-size:12px;color:#334155;\">Generated with primetoolhub.com<\/p>';\r\n                doc += '<' + '\/body><' + '\/html>';\r\n                win.document.write(doc);\r\n                win.document.close();\r\n                win.focus();\r\n                setTimeout(function () { win.print(); win.close(); }, 350);\r\n            },\r\n\r\n            \/* ================= TAB 2: EQUIVALENCE ================= *\/\r\n            runEquiv: function () {\r\n                var e1 = document.getElementById('pth-eq-a').value.trim();\r\n                var e2 = document.getElementById('pth-eq-b').value.trim();\r\n                var verdict = document.getElementById('pth-eq-verdict');\r\n                var render = document.getElementById('pth-eq-render');\r\n                this.clearError('pth-eq-error');\r\n                verdict.style.display = 'none'; render.style.display = 'none';\r\n\r\n                if (!e1 || !e2) { this.showError('pth-eq-error', 'Enter both expressions to compare.'); return; }\r\n\r\n                var t1, t2;\r\n                try { t1 = this.buildTable(e1); } catch (err) { this.showError('pth-eq-error', 'Expression 1: ' + err.message); return; }\r\n                try { t2 = this.buildTable(e2); } catch (err2) { this.showError('pth-eq-error', 'Expression 2: ' + err2.message); return; }\r\n\r\n                \/\/ union of variables so both are evaluated over the same input space\r\n                var seen = {}, vars = [], i, j;\r\n                for (i = 0; i < t1.vars.length; i++) { if (!seen[t1.vars[i]]) { seen[t1.vars[i]] = 1; vars.push(t1.vars[i]); } }\r\n                for (i = 0; i < t2.vars.length; i++) { if (!seen[t2.vars[i]]) { seen[t2.vars[i]] = 1; vars.push(t2.vars[i]); } }\r\n                vars.sort();\r\n                if (vars.length > 8) { this.showError('pth-eq-error', 'Combined expressions use more than 8 variables.'); return; }\r\n\r\n                var n = vars.length, total = Math.pow(2, n), diffs = 0, firstDiff = -1;\r\n                var html = '<table class=\"pth-table\"><thead><tr>';\r\n                for (i = 0; i < n; i++) { html += '<th>' + this.escapeHtml(vars[i]) + '<\/th>'; }\r\n                html += '<th class=\"final\">Expr 1<\/th><th class=\"final\">Expr 2<\/th><th>Match<\/th><\/tr><\/thead><tbody>';\r\n\r\n                for (i = 0; i < total; i++) {\r\n                    var vals = {};\r\n                    for (j = 0; j < n; j++) { vals[vars[j]] = (i >> (n - j - 1)) & 1; }\r\n                    var r1 = this.evalNode(t1.ast, vals);\r\n                    var r2 = this.evalNode(t2.ast, vals);\r\n                    var same = r1 === r2;\r\n                    if (!same) { diffs++; if (firstDiff === -1) { firstDiff = i; } }\r\n                    html += '<tr class=\"' + (same ? '' : 'row-diff') + '\">';\r\n                    for (j = 0; j < n; j++) { html += '<td>' + vals[vars[j]] + '<\/td>'; }\r\n                    html += '<td class=\"' + (r1 ? 'res-true' : 'res-false') + '\">' + r1 + '<\/td>';\r\n                    html += '<td class=\"' + (r2 ? 'res-true' : 'res-false') + '\">' + r2 + '<\/td>';\r\n                    html += '<td>' + (same ? '\\u2713' : '\\u2717') + '<\/td><\/tr>';\r\n                }\r\n                html += '<\/tbody><\/table>';\r\n\r\n                var vHtml;\r\n                if (diffs === 0) {\r\n                    vHtml = '<div class=\"pth-verdict ok\">\\u2705 Equivalent \\u2014 both expressions agree on all ' + total + ' input combinations.<\/div>';\r\n                } else {\r\n                    var fd = {}, bits = [];\r\n                    for (j = 0; j < n; j++) { fd[vars[j]] = (firstDiff >> (n - j - 1)) & 1; bits.push(vars[j] + '=' + fd[vars[j]]); }\r\n                    vHtml = '<div class=\"pth-verdict bad\">\\u274C Not equivalent \\u2014 they differ on ' + diffs + ' of ' + total + ' rows.<\/div>'\r\n                        + '<div class=\"pth-finding pth-f-warn\"><strong>First disagreement:<\/strong> row ' + firstDiff + ' where ' + this.escapeHtml(bits.join(', ')) + '. Highlighted in yellow below.<\/div>';\r\n                }\r\n                verdict.innerHTML = vHtml;\r\n                verdict.style.display = 'block';\r\n                render.innerHTML = html;\r\n                render.style.display = 'block';\r\n                this.showToast(diffs === 0 ? 'Expressions are equivalent' : 'Mismatch found', diffs === 0 ? 'success' : 'error');\r\n            },\r\n\r\n            \/* ================= TAB 3: CANONICAL ================= *\/\r\n            runCanon: function () {\r\n                var expr = document.getElementById('pth-cn-formula').value.trim();\r\n                var out = document.getElementById('pth-cn-out');\r\n                this.clearError('pth-cn-error');\r\n                out.style.display = 'none';\r\n                if (!expr) { this.showError('pth-cn-error', 'Enter a Boolean expression first.'); return; }\r\n\r\n                var d;\r\n                try { d = this.buildTable(expr); }\r\n                catch (e) { this.showError('pth-cn-error', e.message); this.showToast('Syntax error', 'error'); return; }\r\n\r\n                var mins = [], maxs = [], i, j;\r\n                for (i = 0; i < d.rows.length; i++) {\r\n                    if (d.rows[i].out) { mins.push(i); } else { maxs.push(i); }\r\n                }\r\n\r\n                var sopTerms = [], posTerms = [];\r\n                for (i = 0; i < mins.length; i++) {\r\n                    var parts = [];\r\n                    for (j = 0; j < d.vars.length; j++) {\r\n                        var bit = (mins[i] >> (d.vars.length - j - 1)) & 1;\r\n                        parts.push(bit ? d.vars[j] : d.vars[j] + '\\u2019');\r\n                    }\r\n                    sopTerms.push(parts.join(''));\r\n                }\r\n                for (i = 0; i < maxs.length; i++) {\r\n                    var p2 = [];\r\n                    for (j = 0; j < d.vars.length; j++) {\r\n                        var b2 = (maxs[i] >> (d.vars.length - j - 1)) & 1;\r\n                        p2.push(b2 ? d.vars[j] + '\\u2019' : d.vars[j]);\r\n                    }\r\n                    posTerms.push('(' + p2.join(' + ') + ')');\r\n                }\r\n\r\n                document.getElementById('pth-cn-min').textContent = mins.length\r\n                    ? '\\u03A3m(' + mins.join(', ') + ')   \\u2014 ' + mins.length + ' minterm(s)'\r\n                    : 'None \\u2014 the function is always 0 (contradiction).';\r\n                document.getElementById('pth-cn-sop').textContent = sopTerms.length\r\n                    ? 'F = ' + sopTerms.join(' + ')\r\n                    : 'F = 0';\r\n                document.getElementById('pth-cn-max').textContent = maxs.length\r\n                    ? '\\u03A0M(' + maxs.join(', ') + ')   \\u2014 ' + maxs.length + ' maxterm(s)'\r\n                    : 'None \\u2014 the function is always 1 (tautology).';\r\n                document.getElementById('pth-cn-pos').textContent = posTerms.length\r\n                    ? 'F = ' + posTerms.join(' \\u00B7 ')\r\n                    : 'F = 1';\r\n\r\n                out.style.display = 'block';\r\n                this.showToast('Canonical forms derived', 'success');\r\n            },\r\n\r\n            \/* ================= TAB 4: WAVEFORM ================= *\/\r\n            runWave: function () {\r\n                var expr = document.getElementById('pth-wv-formula').value.trim();\r\n                var box = document.getElementById('pth-wv-render');\r\n                var dlBtn = document.getElementById('pth-wv-svg');\r\n                this.clearError('pth-wv-error');\r\n                dlBtn.style.display = 'none';\r\n                if (!expr) { box.textContent = 'Draw a waveform to see the signal diagram.'; this.showError('pth-wv-error', 'Enter a Boolean expression first.'); return; }\r\n\r\n                var d;\r\n                try { d = this.buildTable(expr); }\r\n                catch (e) { box.textContent = ''; this.showError('pth-wv-error', e.message); this.showToast('Syntax error', 'error'); return; }\r\n                if (d.vars.length > 5) { box.textContent = ''; this.showError('pth-wv-error', 'Waveform view supports up to 5 variables (' + d.vars.length + ' given).'); return; }\r\n\r\n                var svg = this.buildWaveSvg(d);\r\n                this.lastSvg = svg;\r\n                box.innerHTML = svg;\r\n                dlBtn.style.display = 'inline-block';\r\n                this.showToast('Waveform drawn', 'success');\r\n            },\r\n\r\n            buildWaveSvg: function (d) {\r\n                var steps = d.rows.length;\r\n                var gutter = 74, stepW = Math.max(26, Math.min(48, Math.floor(760 \/ steps)));\r\n                var rowH = 52, sigH = 26;\r\n                var width = gutter + steps * stepW + 20;\r\n                var height = (d.vars.length + 1) * rowH + 34;\r\n                var i, k, s = '';\r\n\r\n                s += '<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"' + width + '\" height=\"' + height + '\" viewBox=\"0 0 ' + width + ' ' + height + '\" role=\"img\" aria-label=\"Digital timing waveform for ' + this.escapeHtml(d.expr) + '\">';\r\n                s += '<rect x=\"0\" y=\"0\" width=\"' + width + '\" height=\"' + height + '\" fill=\"#ffffff\"\/>';\r\n\r\n                \/\/ vertical step gridlines\r\n                for (i = 0; i <= steps; i++) {\r\n                    var gx = gutter + i * stepW;\r\n                    s += '<line x1=\"' + gx + '\" y1=\"18\" x2=\"' + gx + '\" y2=\"' + ((d.vars.length + 1) * rowH + 8) + '\" stroke=\"#e2e8f0\" stroke-width=\"1\"\/>';\r\n                }\r\n                \/\/ step index labels\r\n                for (i = 0; i < steps; i++) {\r\n                    s += '<text x=\"' + (gutter + i * stepW + stepW \/ 2) + '\" y=\"13\" font-family=\"Inter,sans-serif\" font-size=\"9\" fill=\"#334155\" text-anchor=\"middle\">' + i + '<\/text>';\r\n                }\r\n\r\n                var signals = [];\r\n                for (k = 0; k < d.vars.length; k++) {\r\n                    var seq = [];\r\n                    for (i = 0; i < steps; i++) { seq.push(d.rows[i].vals[d.vars[k]]); }\r\n                    signals.push({ name: d.vars[k], seq: seq, color: '#2563eb' });\r\n                }\r\n                var outSeq = [];\r\n                for (i = 0; i < steps; i++) { outSeq.push(d.rows[i].out); }\r\n                signals.push({ name: 'Y', seq: outSeq, color: '#047857' });\r\n\r\n                for (k = 0; k < signals.length; k++) {\r\n                    var top = 26 + k * rowH;\r\n                    var yHigh = top + 4, yLow = top + 4 + sigH;\r\n                    s += '<text x=\"8\" y=\"' + (yLow - 6) + '\" font-family=\"Inter,sans-serif\" font-size=\"13\" font-weight=\"700\" fill=\"' + (k === signals.length - 1 ? '#047857' : '#0f172a') + '\">' + this.escapeHtml(signals[k].name) + '<\/text>';\r\n                    s += '<line x1=\"' + gutter + '\" y1=\"' + yLow + '\" x2=\"' + (gutter + steps * stepW) + '\" y2=\"' + yLow + '\" stroke=\"#f1f5f9\" stroke-width=\"1\"\/>';\r\n\r\n                    var pts = '', prev = null;\r\n                    for (i = 0; i < steps; i++) {\r\n                        var v = signals[k].seq[i];\r\n                        var y = v ? yHigh : yLow;\r\n                        var x0 = gutter + i * stepW, x1 = x0 + stepW;\r\n                        if (prev !== null && prev !== v) { pts += ' ' + x0 + ',' + (prev ? yHigh : yLow) + ' ' + x0 + ',' + y; }\r\n                        else if (prev === null) { pts += ' ' + x0 + ',' + y; }\r\n                        pts += ' ' + x1 + ',' + y;\r\n                        prev = v;\r\n                    }\r\n                    s += '<polyline points=\"' + pts.replace(\/^\\s+\/, '') + '\" fill=\"none\" stroke=\"' + signals[k].color + '\" stroke-width=\"2.2\" stroke-linejoin=\"round\"\/>';\r\n                }\r\n                s += '<text x=\"8\" y=\"' + (height - 8) + '\" font-family=\"Inter,sans-serif\" font-size=\"10\" fill=\"#334155\">Y = ' + this.escapeHtml(this.nodeStr(d.ast)) + '<\/text>';\r\n                s += '<\/svg>';\r\n                return s;\r\n            },\r\n\r\n            downloadSvg: function () {\r\n                if (!this.lastSvg) { this.showToast('Draw a waveform first', 'info'); return; }\r\n                this.downloadBlob(this.lastSvg, 'timing_waveform.svg', 'image\/svg+xml');\r\n                this.showToast('SVG downloaded', 'success');\r\n            },\r\n\r\n            \/* ================= TAB 5: ANALYSIS ================= *\/\r\n            runAnalysis: function () {\r\n                var expr = document.getElementById('pth-an-formula').value.trim();\r\n                var out = document.getElementById('pth-an-out');\r\n                this.clearError('pth-an-error');\r\n                if (!expr) { this.showError('pth-an-error', 'Enter a Boolean expression first.'); return; }\r\n\r\n                var d;\r\n                try { d = this.buildTable(expr); }\r\n                catch (e) { this.showError('pth-an-error', e.message); this.showToast('Syntax error', 'error'); return; }\r\n\r\n                var total = d.rows.length, trueCnt = 0, i, j, k;\r\n                for (i = 0; i < total; i++) { if (d.rows[i].out) { trueCnt++; } }\r\n\r\n                var html = '';\r\n                if (trueCnt === total) {\r\n                    html += '<div class=\"pth-finding pth-f-ok\"><strong>Tautology.<\/strong> The output is 1 for every one of the ' + total + ' input combinations. This expression is always true.<\/div>';\r\n                } else if (trueCnt === 0) {\r\n                    html += '<div class=\"pth-finding pth-f-crit\"><strong>Contradiction.<\/strong> The output is 0 for all ' + total + ' rows. Nothing can ever satisfy this expression.<\/div>';\r\n                } else {\r\n                    html += '<div class=\"pth-finding pth-f-info\"><strong>Contingency.<\/strong> The output is 1 on ' + trueCnt + ' of ' + total + ' rows, so it depends on the inputs. It is satisfiable but not always true.<\/div>';\r\n                }\r\n\r\n                \/\/ Redundant variable detection\r\n                var n = d.vars.length, redundant = [], active = [];\r\n                for (k = 0; k < n; k++) {\r\n                    var isRed = true;\r\n                    for (i = 0; i < total && isRed; i++) {\r\n                        var vals = {};\r\n                        for (j = 0; j < n; j++) { vals[d.vars[j]] = d.rows[i].vals[d.vars[j]]; }\r\n                        var f1 = this.evalNode(d.ast, vals);\r\n                        vals[d.vars[k]] = vals[d.vars[k]] ? 0 : 1;\r\n                        if (this.evalNode(d.ast, vals) !== f1) { isRed = false; }\r\n                    }\r\n                    if (isRed) { redundant.push(d.vars[k]); } else { active.push(d.vars[k]); }\r\n                }\r\n\r\n                if (redundant.length) {\r\n                    html += '<div class=\"pth-finding pth-f-warn\"><strong>Redundant variable(s): ' + this.escapeHtml(redundant.join(', ')) + '.<\/strong> Flipping ' + (redundant.length === 1 ? 'this input' : 'these inputs') + ' never changes the output, so the circuit can drop ' + (redundant.length === 1 ? 'that pin' : 'those pins') + ' entirely.<\/div>';\r\n                } else {\r\n                    html += '<div class=\"pth-finding pth-f-ok\"><strong>Every variable matters.<\/strong> Each of ' + this.escapeHtml(d.vars.join(', ')) + ' changes the output for at least one input combination.<\/div>';\r\n                }\r\n                html += '<div class=\"pth-finding pth-f-info\"><strong>Active inputs:<\/strong> ' + (active.length ? this.escapeHtml(active.join(', ')) : 'none') + ' &nbsp;|&nbsp; <strong>Rows:<\/strong> ' + total + ' &nbsp;|&nbsp; <strong>Satisfiable:<\/strong> ' + (trueCnt > 0 ? 'yes' : 'no') + '<\/div>';\r\n\r\n                out.innerHTML = html;\r\n                this.showToast('Analysis complete', 'success');\r\n            },\r\n\r\n            \/* ================= UTIL ================= *\/\r\n            copyText: function (text) {\r\n                var self = this;\r\n                if (!text) { self.showToast('Nothing to copy yet', 'info'); return; }\r\n                if (navigator.clipboard && navigator.clipboard.writeText) {\r\n                    navigator.clipboard.writeText(text).then(function () { self.showToast('Copied to clipboard', 'success'); })\r\n                        .catch(function () { self.showToast('Copy blocked by browser', 'error'); });\r\n                } else { self.showToast('Clipboard not supported', 'error'); }\r\n            },\r\n\r\n            showToast: function (msg, type) {\r\n                var wrap = document.getElementById('pth-tt-toast-wrap');\r\n                if (!wrap) { return; }\r\n                var t = document.createElement('div');\r\n                t.className = 'pth-toast ' + (type || 'info');\r\n                t.setAttribute('role', 'status');\r\n                t.textContent = msg;\r\n                wrap.appendChild(t);\r\n                setTimeout(function () { if (t.parentNode) { t.parentNode.removeChild(t); } }, 3000);\r\n            }\r\n        };\r\n\r\n        \/* ---------- 4-Layer Bootstrap ---------- *\/\r\n        function pthTtInit() {\r\n            if (!window.pthTruthTableApp.initialized && document.getElementById('pth-tt-studio-wrapper')) {\r\n                window.pthTruthTableApp.initialized = true;\r\n                window.pthTruthTableApp.init();\r\n            }\r\n        }\r\n        pthTtInit();\r\n        if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', pthTtInit); }\r\n        window.addEventListener('load', function () { setTimeout(pthTtInit, 50); });\r\n        if (!window.pthTruthTableApp.initialized && typeof MutationObserver !== 'undefined') {\r\n            var pthTtObs = new MutationObserver(function () {\r\n                if (document.getElementById('pth-tt-studio-wrapper')) { pthTtObs.disconnect(); pthTtInit(); }\r\n            });\r\n            pthTtObs.observe(document.body || document.documentElement, { childList: true, subtree: true });\r\n            setTimeout(function () { pthTtObs.disconnect(); }, 10000);\r\n        }\r\n    })();\r\n    <\/script>\r\n<\/div>\n\n\n\n\n<style>\n.pth-container{max-width:1480px;margin:0 auto;padding:0 20px;box-sizing:border-box}\n.pth-feature-wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px;margin-bottom:40px}\n.pth-feat-box{border:1px solid #e2e8f0;background:#fff;padding:24px;border-radius:12px;box-shadow:0 4px 6px -1px rgba(0,0,0,0.02);transition:all .3s ease}\n.pth-feat-box:hover{border-color:#bfdbfe;transform:translateY(-3px);box-shadow:0 10px 15px -3px rgba(0,0,0,0.05)}\n.pth-feat-title{font-size:1.05rem;font-weight:800;color:#0f172a;margin:0 0 10px;display:flex;align-items:center;gap:10px}\n.pth-feat-text{font-size:.9rem;color:#1e293b;line-height:1.6;margin:0;font-weight:500}\n.pth-steps-wrap{border:1px solid #e2e8f0;background:#fff;padding:40px 30px;border-radius:16px;text-align:center;box-shadow:0 4px 6px -1px rgba(0,0,0,0.02);margin-bottom:40px;width:100%;box-sizing:border-box}\n.pth-steps-title{font-size:1.2rem;font-weight:800;color:#0f172a;text-transform:uppercase;margin:0 0 35px;letter-spacing:1px}\n.pth-steps-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:30px}\n.pth-step-item{display:flex;flex-direction:column;align-items:center}\n.pth-step-num{width:45px;height:45px;background:#2563eb;color:#fff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:1.2rem;margin-bottom:15px;box-shadow:0 4px 10px rgba(37,99,235,.3)}\n.pth-step-name{font-weight:800;color:#0f172a;margin:0 0 8px;font-size:1rem}\n.pth-step-desc{font-size:.9rem;color:#1e293b;line-height:1.5;margin:0;font-weight:500}\n<\/style>\n<div class=\"pth-container\">\n  <div class=\"pth-feature-wrap\">\n    <div class=\"pth-feat-box\">\n      <p class=\"pth-feat-title\"><span aria-hidden=\"true\">\ud83d\udfe2<\/span> Build the table, see the working<\/p>\n      <p class=\"pth-feat-text\">Type an expression and every input combination is evaluated at once. Variables are detected for you, and each bracketed sub-expression gets its own column so you can follow how the final result was reached rather than just trusting it.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n      <p class=\"pth-feat-title\"><span aria-hidden=\"true\">\ud83d\udd35<\/span> Prove two expressions match<\/p>\n      <p class=\"pth-feat-text\">The Equivalence tab compares two expressions row by row. If they agree everywhere you get a clear verdict; if they do not, it names the exact input combination where they first disagree and highlights that row in yellow.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n      <p class=\"pth-feat-title\"><span aria-hidden=\"true\">\ud83d\udfe3<\/span> Read it as terms, waves or warnings<\/p>\n      <p class=\"pth-feat-text\">The same table becomes a minterm and maxterm list, a digital timing waveform you can download as SVG, and a short audit that tells you whether the expression is always true, never true, or quietly ignoring one of its inputs.<\/p>\n    <\/div>\n  <\/div>\n  <div class=\"pth-steps-wrap\">\n    <p class=\"pth-steps-title\">How to Use the Truth Table Studio<\/p>\n    <div class=\"pth-steps-grid\">\n      <div class=\"pth-step-item\">\n        <div class=\"pth-step-num\" aria-hidden=\"true\">1<\/div>\n        <p class=\"pth-step-name\">Truth Table<\/p>\n        <p class=\"pth-step-desc\">Type an expression, or tap the operator keys. Press Generate for the full table, stats and Verilog module.<\/p>\n      <\/div>\n      <div class=\"pth-step-item\">\n        <div class=\"pth-step-num\" aria-hidden=\"true\">2<\/div>\n        <p class=\"pth-step-name\">Equivalence<\/p>\n        <p class=\"pth-step-desc\">Paste your original and your simplified version. One click tells you whether the simplification is safe.<\/p>\n      <\/div>\n      <div class=\"pth-step-item\">\n        <div class=\"pth-step-num\" aria-hidden=\"true\">3<\/div>\n        <p class=\"pth-step-name\">Canonical &amp; Waveform<\/p>\n        <p class=\"pth-step-desc\">Derive \u03a3m and \u03a0M lists, then draw the timing diagram to see the output track the inputs step by step.<\/p>\n      <\/div>\n      <div class=\"pth-step-item\">\n        <div class=\"pth-step-num\" aria-hidden=\"true\">4<\/div>\n        <p class=\"pth-step-name\">Logic Analysis<\/p>\n        <p class=\"pth-step-desc\">Classify the expression and find any variable that never changes the output, so you can drop it from the circuit.<\/p>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n \n\n\n\n<p class=\"wp-block-paragraph\">Last updated: July 2026<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-when-the-logic-works-on-paper-but-not-on-the-breadboard\" class=\"wp-block-heading\">\ud83d\udd34&nbsp;<strong>When the logic works on paper but not on the breadboard<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You wired the circuit, powered it up, and one input combination gives the wrong light. The temptation is to start swapping chips. The faster move is to write the expression down and let the table show you all of it at once, because a truth table is the complete specification of a combinational circuit. Nothing hides in it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Try a real one. Enter&nbsp;(A AND B) OR (NOT C)&nbsp;and the studio produces eight rows for three variables. Leave &#8220;Show intermediate steps&#8221; ticked and you also get a column for&nbsp;A AND B&nbsp;and a column for&nbsp;NOT C. Now the row where A=0, B=1, C=0 stops being a mystery: the AND column is 0, the NOT C column is 1, so the OR gives 1. If your board says 0 for that combination, the fault is in the wiring or the chip, not in your algebra. That distinction saves an evening.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The keyboard under the input accepts words or symbols, so&nbsp;A AND B,&nbsp;A &amp; B&nbsp;and&nbsp;AB-style engineering notation with a trailing apostrophe for NOT all parse the same way. XOR, XNOR, NAND, NOR, IMPLIES and IFF are all supported, evaluated by a parser built into the page rather than by handing your text to the browser&#8217;s code evaluator.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe1-proving-a-simplification-did-not-change-the-circuit\" class=\"wp-block-heading\">\ud83d\udfe1&nbsp;<strong>Proving a simplification did not change the circuit<\/strong><\/h2>\n\n\n<figure class=\"pth-article-figure pth-img-left\" style=\"float:left; width:700px; max-width:100%; margin:4px 28px 16px 0; clear:left;\"><img decoding=\"async\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/07\/boolean-equivalence-mismatch-800x447.jpeg\" alt=\"Two Boolean expressions compared row by row with one mismatching row highlighted\" width=\"700\" height=\"394\" loading=\"lazy\" data-no-lazy=\"1\" class=\"pth-article-img\" style=\"width:100%;height:auto;display:block;border-radius:10px;border:1px solid #e2e8f0;\"><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Simplifying Boolean algebra is where marks and hours get lost. You apply De Morgan&#8217;s law, cancel a term, arrive at something shorter, and then quietly wonder whether it still does the same job. The Equivalence tab answers that in one click, and it is the reason this studio exists rather than just another table generator.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Put&nbsp;NOT (A AND B)&nbsp;in the first box and&nbsp;(NOT A) OR (NOT B)&nbsp;in the second. Both are evaluated over the union of their variables, and you get a green verdict: equivalent on all four rows. Now change the second one to&nbsp;(NOT A) AND (NOT B), the mistake almost everyone makes once. The verdict turns red, it tells you they differ on two of four rows, and it names the first disagreement, A=0 and B=1, with that row shaded yellow in the table below. Seeing the exact failing input is what turns a wrong answer into an understood one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Two habits follow from this. Check every simplification against the original before you commit it to a circuit. And when a lecturer&#8217;s answer differs from yours, compare the two expressions here first, because quite often both are correct and merely written differently.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe2-the-same-table-as-terms-as-waves-and-as-a-warning\" class=\"wp-block-heading\">\ud83d\udfe2&nbsp;<strong>The same table as terms, as waves, and as a warning<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A truth table has more than one useful reading. The Canonical Forms tab lists the rows where the output is 1 as minterms, written&nbsp;\u03a3m(0, 2, 4, 6, 7)&nbsp;for the example above, and the rows where it is 0 as maxterms. From those two lists it writes out the canonical sum-of-products and product-of-sums. These are the exact forms your textbook asks for, and they are the input a Karnaugh map needs. The studio deliberately stops there rather than minimising, so hand the minterm list to the&nbsp;<a href=\"https:\/\/schoolict.net\/tools\/advanced-k-map-solver\/\" rel=\"noreferrer noopener\" target=\"_blank\">K-Map Solver<\/a>&nbsp;or the&nbsp;<a href=\"https:\/\/schoolict.net\/tools\/boolean-expression-simplifier\/\" rel=\"noreferrer noopener\" target=\"_blank\">Boolean Expression Simplifier<\/a>&nbsp;when you want the smallest expression.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Timing Waveform tab redraws the table as a digital signal diagram, the view a logic analyser would give you. Inputs count up in binary while the output rises and falls beneath them, which makes the behaviour of something like&nbsp;A XOR B&nbsp;obvious in a way a grid of ones and zeros never quite is. It downloads as an SVG, so it drops straight into a lab report at any size without going blurry.<\/p>\n\n\n\n<h3 id=\"\ud83d\udfe2-the-check-that-pays-for-itself-redundant-variables\" class=\"wp-block-heading\">\ud83d\udfe2&nbsp;<strong>The check that pays for itself: redundant variables<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\ud83d\udd35 Run Logic Analysis on&nbsp;A OR (B AND NOT B)&nbsp;and it reports that B is redundant, because flipping B never changes the output.<br>\ud83d\udfe0 In hardware that is a wasted input pin, a wasted trace, and a gate you are paying for.<br>\ud83d\udfe3 The same tab flags a tautology, where the output is always 1, and a contradiction, where it is always 0. Both usually mean a typo rather than a design.<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-honest-limits-and-where-to-go-next\" class=\"wp-block-heading\">\ud83d\udd34&nbsp;<strong>Honest limits, and where to go next<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Eight variables is the ceiling, because that is already 256 rows and the table stops being something a human reads. The waveform view caps lower still, at five variables and thirty-two time steps, since past that the traces become too narrow to follow. This is combinational logic only: there are no flip-flops, no clocks and no memory, so a sequential circuit with feedback cannot be described here. The Canonical Forms tab gives you canonical expressions, never minimal ones, and saying otherwise would be a lie you would discover in your next assignment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One button leaves your machine. &#8220;Simulate on DigitalJS&#8221; opens an external browser-based Verilog simulator in a new tab with your generated module encoded in the link, which is handy for watching gate-level propagation. Everything else, the parser included, runs locally with no&nbsp;eval&nbsp;and no network calls. When you need the physical chip that implements your expression, the&nbsp;<a href=\"https:\/\/schoolict.net\/tools\/7400-series-ic-finder\/\" rel=\"noreferrer noopener\" target=\"_blank\">7400 Series IC Finder<\/a>&nbsp;maps gates to real pinouts, and if the binary row indices in the minterm list are unfamiliar, our&nbsp;<a href=\"https:\/\/schoolict.net\/tools\/number-base-converter-calculator-article\/\" rel=\"noreferrer noopener\" target=\"_blank\">guide to number bases<\/a>&nbsp;explains how those row numbers are built. The 7400 family itself is documented in detail on&nbsp;<a href=\"https:\/\/en.wikipedia.org\/wiki\/7400-series_integrated_circuits\" rel=\"noreferrer noopener\" target=\"_blank\">Wikipedia&#8217;s 7400-series page<\/a>.<\/p>\n\n\n\n\n<style>\n.pth-faq-section{margin:50px auto 40px;font-family:inherit;max-width:1480px;padding:0 20px;box-sizing:border-box}\n.pth-faq-header{font-size:1.8rem;font-weight:800;color:#0f172a;margin-bottom:25px;border-bottom:2px solid #e2e8f0;padding-bottom:10px;display:flex;align-items:center;gap:10px}\n.pth-faq-grid{display:grid;grid-template-columns:1fr;gap:20px}\n@media(min-width:768px){.pth-faq-grid{grid-template-columns:repeat(2,1fr)}}\n@media(min-width:1024px){.pth-faq-grid{grid-template-columns:repeat(3,1fr)}}\n.pth-faq-card{background:#f8fafc;padding:24px;border-radius:12px;border:1px solid #e2e8f0;transition:transform .2s ease;break-inside:avoid}\n.pth-faq-card:hover{transform:translateY(-3px);box-shadow:0 4px 12px rgba(0,0,0,.05)}\n.pth-faq-q{color:#0f172a;font-size:1rem;font-weight:700;margin:0 0 12px;line-height:1.4}\n.pth-faq-a{margin:0;font-size:.95rem;color:#1e293b;line-height:1.6;font-weight:500}\n<\/style>\n<div class=\"pth-faq-section\">\n  <div class=\"pth-faq-header\">\u2753 Frequently Asked Questions<\/div>\n  <div class=\"pth-faq-grid\">\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Which operators are supported?<\/p>\n      <p class=\"pth-faq-a\">AND, OR, NOT, XOR, XNOR, NAND, NOR, IMPLIES and IFF, in words or as symbols such as &amp;, |, !, ^, -&gt; and a trailing apostrophe for NOT. Constants 0 and 1 are valid too.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">How many variables can it handle?<\/p>\n      <p class=\"pth-faq-a\">Up to eight, which is 256 rows. The Timing Waveform tab is capped at five variables so the traces stay wide enough to read.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Does it simplify the expression?<\/p>\n      <p class=\"pth-faq-a\">No. It gives canonical minterm and maxterm forms, where every term is written in full. For a minimal expression, send the minterm list to the K-Map Solver or the Boolean Expression Simplifier.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">What does a redundant variable mean?<\/p>\n      <p class=\"pth-faq-a\">It means flipping that input never changes the output, so the circuit does not actually need it. Logic Analysis names any such variable, which usually points at a term that cancels itself.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Can it check my simplification homework?<\/p>\n      <p class=\"pth-faq-a\">Yes, that is what the Equivalence tab is for. Enter the original and your simplified version. If they differ, it shows the first input combination where the outputs disagree.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Is my expression sent to a server?<\/p>\n      <p class=\"pth-faq-a\">No. The parser is written into the page and runs on your device, with no code evaluator and no network calls. The only exception is the DigitalJS button, which deliberately opens an external simulator.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Does it support flip-flops or clocked circuits?<\/p>\n      <p class=\"pth-faq-a\">No. Truth tables describe combinational logic, where the output depends only on the current inputs. Sequential circuits with memory and feedback need a state diagram instead.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">What is the Verilog export for?<\/p>\n      <p class=\"pth-faq-a\">It writes a ready module with your variables as inputs and the expression as a single assign statement. Copy it, download it as a .v file, or open it in DigitalJS to watch the gates switch.<\/p>\n    <\/div>\n    <div class=\"pth-faq-card\">\n      <p class=\"pth-faq-q\">Why do the row numbers matter?<\/p>\n      <p class=\"pth-faq-a\">Each row index is the binary value of the inputs read top to bottom, and those indices are exactly what a minterm list \u03a3m(&#8230;) refers to. They are also the cell addresses a Karnaugh map expects.<\/p>\n    <\/div>\n  <\/div>\n<\/div>\n \n","protected":false},"excerpt":{"rendered":"<p>Truth Table Studio Instantly generate truth tables, simplify Boolean logic, and convert expressions to NAND\/NOR gates with Verilog HDL code. \ud83d\udfe2 Build the table, see the working Type an expression and every input combination is evaluated at once. Variables are detected for you, and each bracketed sub-expression gets its own column so you can follow &#8230; <a title=\"Truth Table Generator | Generate, Compare &amp; Analyse Boolean Logic Offline\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/truth-table-generator\/\" aria-label=\"Read more about Truth Table Generator | Generate, Compare &amp; Analyse Boolean Logic Offline\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":226,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-31","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/31","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/comments?post=31"}],"version-history":[{"count":0,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/31\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/226"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=31"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}