feat: add spi_slave.v physical layer (Phase 4 SPI RTL, part 1/N)
First real RTL piece of the SPI interface (docs §8.1 protocol draft): the physical layer only -- Mode 0 (CPOL=0, CPHA=0), MSB-first, byte-level shift register with a 3-stage CDC synchronizer for SCLK/MOSI/CS_N (the SPI master clock is asynchronous to the FPGA system clock). Exposes rx_byte/rx_valid, tx_byte/tx_byte_req, and cs_active/cs_start/cs_end to the (not yet written) protocol engine. Documented an important consumer contract on tx_byte_req: it is a prefetch hint (fires once extra after the last byte of every transaction, since the slave cannot know in advance whether the master will keep clocking), not a "byte consumed" event -- a consumer must advance any stateful pointer (e.g. a RAM read address) on rx_valid instead, which fires exactly once per real byte transferred. sim/spi_slave_tb.v: bit-banged SPI master BFM (4 tests: single byte, multi-byte in one CS period, back-to-back transactions, slower SCLK). Two testbench-only bugs found and fixed during bring-up (RTL itself needed no functional change beyond the tx_byte_req contract comment): the BFM was advancing its tx queue on tx_byte_req instead of rx_valid (see contract above), and inter-test reset pulses raced against posedge clk (blocking `rst=1` landing on the same simulation time as a clock edge) -- fixed by asserting/deasserting reset on negedge clk instead. Verified two ways: Icarus Verilog (4/4 tests pass) and the real ECP5 toolchain used for prior benchmarks (Yosys 0.68 synth: 0 problems, 41 FF / 55 LUT4, no latches; nextpnr-ecp5 --45k --package CABGA381 --speed 8 --freq 80: PASS, Fmax 403.23 MHz; ecppack: bitstream generated with no errors). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WQV3vS9TXaGDJ5cRfnfidt
This commit is contained in: