
This project implements a 1-bit artificial neuron (perceptron) in pure combinational logic on silicon.
The design computes the fundamental neuron equation:
$y = (x_0 \cdot w_0 + x_1 \cdot w_1 + x_2 \cdot w_2 + x_3 \cdot w_3) \geq \text{threshold}$
where:
Dedicated Inputs (ui_in[7:0])
ui_in[3:0]: Binary inputs x₀, x₁, x₂, x₃ui_in[5:4]: Weight w₀ (2 bits, value 0–3)ui_in[7:6]: Weight w₁ (2 bits, value 0–3)Bidirectional IOs (uio_in[7:0])
uio_in[1:0]: Weight w₂ (2 bits, value 0–3)uio_in[3:2]: Weight w₃ (2 bits, value 0–3)uio_in[5:4]: Threshold config (2 bits; actual threshold = config + 1, so 1–4)uio_in[7:6]: UnusedDedicated Outputs (uo_out[7:0])
uo_out[0]: Neuron output y (1 if fires, 0 if silent)uo_out[4:1]: Weighted sum (4-bit debug output, range 0–12)uo_out[7:5]: Unused (tied low)The design uses a three-stage datapath:
This is purely combinational logic (no clock, no state), so the output is valid the instant all inputs are set.
The design includes a comprehensive cocotb testbench covering five key neuron behaviors.
cd test/
make
This builds the RTL simulation using Icarus Verilog and runs all testbench modules via cocotb.
test_zero_inputs: Verifies the neuron remains silent when all inputs are 0, regardless of weights or threshold.
test_or_gate: Configures the neuron as an OR gate (w₀=w₁=w₂=w₃=1, threshold=1). The neuron should fire if any input is 1.
test_and_gate: Configures the neuron as an AND gate (w₀=w₁=w₂=w₃=1, threshold=4). The neuron fires only when all four inputs are 1.
test_weighted_sum: Tests the arithmetic of the weighted sum stage with hand-calculated cases:
test_threshold_sweep: Verifies the firing boundary by sweeping the threshold:
The testbench generates a waveform file (tb.fst). To visualize with GTKWave:
gtkwave tb.fst tb.gtkw
None. This is a pure digital design with no external dependencies.
| # | Input | Output | Bidirectional |
|---|---|---|---|
| 0 | x0 — binary input 0 | y — neuron output (1=fires, 0=silent) | w2[0] — weight 2, bit 0 |
| 1 | x1 — binary input 1 | sum[0] — weighted sum bit 0 (debug) | w2[1] — weight 2, bit 1 |
| 2 | x2 — binary input 2 | sum[1] — weighted sum bit 1 (debug) | w3[0] — weight 3, bit 0 |
| 3 | x3 — binary input 3 | sum[2] — weighted sum bit 2 (debug) | w3[1] — weight 3, bit 1 |
| 4 | w0[0] — weight 0, bit 0 | sum[3] — weighted sum bit 3 (debug) | thresh[0] — threshold bit 0 |
| 5 | w0[1] — weight 0, bit 1 | unused | thresh[1] — threshold bit 1 |
| 6 | w1[0] — weight 1, bit 0 | unused | unused |
| 7 | w1[1] — weight 1, bit 1 | unused | unused |