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] |