
The design is a fully synthesizable, stream-oriented SHA‑256 implementation built from four simple modules. It consumes a byte stream that has already been padded according to FIPS 180‑4 (§5.1.1), performs the compression over 512‑bit blocks, and emits the 256‑bit digest as 32 raw bytes (MSB first).
sha256_core_v3: Compression engine for a single 512‑bit block.
w[0..15]).first_run.ready when the block is complete; digest is available on hash_out.sha256_k_rom_soft: Small combinational ROM supplying the 64 K‑constants indexed by the round counter.
sha256_processor: Byte‑stream front‑end for the core.
block_buffer.IDLE → LOAD → HASH → DONE.start to mark the first byte of a message and data_last to mark the final (already padded) byte of the full message.first_run=0.in_ready to indicate when the next byte may be accepted.top_gpio_sha256: Tiny Tapeout‑friendly GPIO wrapper.
in_ready momentarily de‑asserts.IDLE → FEED → WAIT → DUMP.
sha256_processor while in_ready is high.done for the full message.dout with dvalid asserted; bytes are sent MSB‑first (hash[255:248] … hash[7:0]).ready indicator so the host can throttle transmission.tt_um_sha256_processor_dvirdc: Tiny Tapeout user‑module wrapper.
ui_in, uo_out, and uio_* busses.rst_n to the active‑high rst used internally.tt_um_sha256_processor_dvirdc
└─ top_gpio_sha256
└─ sha256_processor
├─ sha256_core_v3
└─ sha256_k_rom_soft
All I/O are synchronous to clk. Reset is synchronous, active‑high inside the design (rst = ~rst_n).
Inputs
ui_in[7:0] — data byteuio_in[0] — VALID (assert for one clock when ui_in is valid)uio_in[1] — LAST (assert together with the final, already‑padded byte of the message)Outputs
uo_out[7:0] — digest byte stream (MSB‑first)uio_out[2] — DVALID (digest byte valid strobe during the 32‑cycle dump)uio_out[3] — BUSY (high from first accepted byte until digest dump completes)uio_out[4] — READY (high when the design can accept the next input byte)Output‑enable
uio_oe = 8'b0001_1100 so bits [4,3,2] are driven by the design; other uio_* bits are inputs.rst_n=0 for a few cycles, then rst_n=1).READY=1.ui_in[7:0].VALID for one clock. Assert LAST only with the final padded byte.READY=0, pause and retry when READY returns high (the 2‑byte skid buffer absorbs short stalls).uo_out[7:0] with DVALID=1 each cycle. Collect all 32 bytes to form the digest.Notes:
hash[255:248] first … hash[7:0] last.From the test/ directory:
cd test
make -B # runs cocotb against the RTL sources
Key testbench: test/test_gpio_sha256.py.
sha256_pad() to pad messages on the host, then streams the padded bytes via the GPIO protocol above.hashlib.sha256(message).digest().Minimal host‑side example of padding and streaming logic (conceptual):
def sha256_pad(msg: bytes) -> bytes:
padded = msg + b"\x80"
padded += b"\x00" * ((56 - (len(msg) + 1) % 64) % 64)
padded += (len(msg) * 8).to_bytes(8, "big")
return padded
# For each byte in sha256_pad(message):
# wait until READY == 1
# drive ui_in[7:0] = byte
# pulse VALID for one clk (and LAST with the final byte only)
# Read 32 bytes when DVALID == 1 to obtain the digest (MSB-first)
Drive the GPIO streaming signals via your harness or a small microcontroller/FPGA test jig at 3.3 V logic levels. Follow the protocol above. No UART is required for the default build.
Legacy UART tops (src/old_modules/top_uart_sha256*.v) are provided for reference but are not used by the Tiny Tapeout wrapper in this project.
For FPGA I used Tang Nano 9k and the top module is available on src/old_modules/top_wrapper_tang9k.v
No special peripherals are required. The design runs from the Tiny Tapeout 50 MHz clock and uses standard GPIO‑level handshakes. If desired, LEDs can be connected to observe BUSY/DVALID activity.
| # | Input | Output | Bidirectional |
|---|---|---|---|
| 0 | DATA_IN[0] | DATA_OUT[0] | VALID_IN |
| 1 | DATA_IN[1] | DATA_OUT[1] | LAST_IN |
| 2 | DATA_IN[2] | DATA_OUT[2] | DVALID_OUT |
| 3 | DATA_IN[3] | DATA_OUT[3] | BUSY_OUT |
| 4 | DATA_IN[4] | DATA_OUT[4] | READY_OUT |
| 5 | DATA_IN[5] | DATA_OUT[5] | |
| 6 | DATA_IN[6] | DATA_OUT[6] | |
| 7 | DATA_IN[7] | DATA_OUT[7] |