
This design combines two IP blocks:
spi_mem_ctrl): A small FSM that reads bytes from an external SPI RAM using command 0x03 (read) plus a 16-bit address. It drives cs_n, sck, and mosi, samples miso, and exposes busy/valid along with the received byte.vga_sync): Generates 640x480 @ 60 Hz timing. It produces hsync, vsync, display_on, and pixel coordinates (screen_hpos, screen_vpos).ui_in[0] selects the mode:
ui_in[0]=0): uo_out outputs the raw SPI byte. ui_in[1] is a start pulse, ui_in[2] is last, and ui_in[7:4] select the high address nibble.ui_in[0]=1): uo_out outputs VGA timing + 2-bit RGB (6-bit color). Bytes fetched from SPI are latched into pixel_col.rst_n).ui_in[0]=0, pulse ui_in[1] for one cycle, set ui_in[2] for single-byte read, and set ui_in[7:4] for address high nibble. Observe uio_out[7:5] for {busy, valid, last} and read the byte on uo_out when valid goes high.ui_in[0]=1, feed a 25.175 MHz pixel clock, and observe uo_out for HS, VS, and 2-bit RGB.Use the cocotb test in test/ to exercise the SPI path in simulation.
miso).hsync/vsync timing (optional for simulation).| # | Input | Output | Bidirectional |
|---|---|---|---|
| 0 | MODE (0=SPI, 1=VGA) | SPI_DATA[0] / VGA_R1 | SPI_CS_N |
| 1 | SPI_START | SPI_DATA[1] / VGA_G1 | SPI_SCK |
| 2 | SPI_LAST | SPI_DATA[2] / VGA_B1 | SPI_MOSI |
| 3 | SPI_RST | SPI_DATA[3] / VGA_VSYNC | SPI_MISO |
| 4 | ADDR_HI[0] / VGA_RST | SPI_DATA[4] / VGA_R0 | SPI_DATA[6] |
| 5 | ADDR_HI[1] | SPI_DATA[5] / VGA_G0 | SPI_DATA[7] |
| 6 | ADDR_HI[2] | SPI_DATA[6] / VGA_B0 | SPI_VALID |
| 7 | ADDR_HI[3] | SPI_DATA[7] / VGA_HSYNC | SPI_BUSY |