Guide for implementing combinational/sequential logic circuits using gate-level descriptions in text-based simulators. This skill applies when building circuits for mathematical functions like integer
This skill provides guidance for implementing mathematical computations as gate-level circuits. It covers combinational logic (adders, comparators, multiplexers) and sequential logic (feedback-based iteration) in text-based circuit simulators that use event-driven simulation.
When to Use This Skill
Use this skill when:
Building circuits that compute mathematical functions (square root, Fibonacci, etc.)
Working with text-based gate netlists (e.g., gates.txt format)
Implementing multi-bit arithmetic operations at the gate level
Debugging circuits in event-driven simulators with feedback loops
Optimizing gate counts to meet resource constraints
Approach: Component-First Development
Step 1: Understand the Simulator Semantics
Before writing any circuit code:
- Examine any provided example gate files to understand:
Verwandte Skills
Read example files carefully
Input signal handling (e.g., out{i} = out{i} pattern for preserving inputs)
Gate syntax and argument ordering
How feedback loops are represented
Establish conventions - Document clearly:
Mux semantics: Does mux(sel, a, b) select a when sel=0 or sel=1?
Signal naming conventions
Bit ordering (LSB vs MSB first)
Test simulator behavior - Create minimal test circuits to verify:
Feedback loop behavior (toggle tests)
Multi-cycle convergence
Event-driven vs synchronous semantics
Step 2: Paper-Trace Algorithms First
Before implementing complex algorithms:
Work through small examples by hand - For integer square root, trace through isqrt(16), isqrt(17), isqrt(100)
Verify mathematical correctness - Ensure formulas are correct before coding (e.g., Newton-Raphson, binary search bounds)
Identify iteration counts - Determine how many iterations are needed for the input range
Step 3: Estimate Resource Usage
Before implementation:
Calculate expected gate counts - A 32-bit multiplier may require 30,000+ gates
Compare against limits - If limit is 32,000 gates, avoid multiplication-heavy approaches
N-bit subtractor (adder with inverted operand + carry-in)
N-bit comparator (A < B, A == B)
Test each component:
Unit test adders with known values
Verify comparators with edge cases (0, max value, equal values)
Test mux selection in both directions
Step 5: Implement Algorithm-Specific Logic
For isqrt (integer square root):
Binary search approach: Start with bounds [0, 2^16], narrow by comparing mid^2 with input
Avoid direct multiplication if gate-constrained; use iterative addition or precomputed squares
Handle edge cases: isqrt(0)=0, isqrt(1)=1
For Fibonacci:
Implement as sequential state machine using feedback
Two registers: fib_prev and fib_curr
Iterate based on iteration count from isqrt result
Handle edge cases: fib(0)=0, fib(1)=1
Step 6: Combine and Integrate
When combining components:
Use clear signal naming to track data flow
Verify interface widths match between components
Test the combined circuit with known input/output pairs
Verification Strategies
Unit Testing
Test primitives in isolation - Create separate test scripts for each component
Use known test vectors - For adders: 0+0=0, 1+1=2, max+1=overflow
Edge case coverage:
Zero inputs
Maximum value inputs
Boundary conditions (e.g., perfect squares for isqrt)
Integration Testing
Test with small inputs first - Verify fib(isqrt(1)), fib(isqrt(4)), fib(isqrt(9))
Verify intermediate values - Check isqrt output before Fibonacci computation
Test large inputs - Ensure overflow handling works correctly
Debugging Techniques
Add debug outputs - Temporarily expose internal signals for inspection
Trace signal propagation - Follow a known input through the circuit manually
Binary search for bugs - If output is wrong, test intermediate stages to isolate the issue
Common Pitfalls
Input Signal Handling
Mistake: Not preserving input signals in the gate file.
Solution: Many simulators require explicit input preservation:
out0 = out0 # Preserve input bit 0
out1 = out1 # Preserve input bit 1
...
Read example files to identify this pattern before implementation.
Algorithm Implementation Errors
Mistake: Implementing formulas without verification.
Example: Using test_val = 2*res + 1 when the correct formula is different for the chosen iteration method.
Solution: Paper-trace the algorithm with concrete values before coding.
Gate Count Explosion
Mistake: Using multiplication without estimating gate cost.
Example: A 32x32 multiplier can require 30,000+ gates, exceeding typical limits.
Solution:
Estimate gates before implementation
Prefer comparison-based or additive approaches when possible
Consider iterative algorithms that reuse circuitry
Off-by-One Errors
Mistake: Getting fib(k-1) instead of fib(k) due to iteration count errors.
Solution:
Clearly define what iteration 0, 1, 2, ... produce
Trace through fib(0), fib(1), fib(2) by hand to verify indexing
Feedback Loop Confusion
Mistake: Misunderstanding how feedback stabilizes in event-driven simulation.
Example: A toggle test showing 0 after even iterations is correct, not broken.
Solution:
Test feedback loops with minimal circuits first
Understand that value after N steps depends on initial value and operation
Mux Argument Order
Mistake: Confusing which input is selected when selector is 0 vs 1.
Solution:
Establish and document convention at the start
Test with a minimal mux circuit before using in larger designs
Recommended Workflow
Read all provided examples and documentation
Paper-trace the algorithm with test values
Estimate gate counts for chosen approach
Build and test primitive gates
Build and test arithmetic components
Build and test algorithm-specific logic
Integrate components
Test with edge cases
Optimize if needed (reduce gates, fix bugs)
Testing Checklist
Input signals preserved correctly
Adder produces correct sums
Comparator handles all cases (less, equal, greater)
isqrt(0) = 0
isqrt(1) = 1
isqrt(perfect square) = exact root
fib(0) = 0
fib(1) = 1
Combined circuit matches expected outputs
Gate count within limits
Overview
This skill guides implementing combinational and sequential gate-level circuits for mathematical functions like integer square root and Fibonacci. It focuses on text-based netlist development for event-driven simulators and on practical strategies to manage gate counts, correctness, and feedback behavior. The goal is reliable, testable circuits that fit simulator and resource constraints.
How this skill works
Start by learning the simulator's netlist syntax, signal naming, bit ordering, and mux semantics. Develop and unit-test primitive gates (AND/OR/XOR/NOT, MUX) and arithmetic blocks (adders, subtractors, comparators) before composing algorithm-specific logic. For sequential designs, implement registers and feedback loops as small state machines and verify multi-cycle convergence with minimal test benches.
When to use it
When building gate-level netlists for isqrt, Fibonacci, or similar arithmetic functions
When working with text-based, event-driven circuit simulators that require explicit signal preservation