This is not a cycle-perfect zx spectrum compatible computer and, to be honest, it is not perfect at all. But it works and was able to run all games I've already tried. The intention was to create a computer using mostly technologies of years 1980-1990 so all components are THT except USB-C connector and jack connectors. And, of course, WeACT rp2350b Core board, but it is also kind of THT :)
No SD cards, no other speed-loading methods. You can only use your cassette recorder or smartphone to load/save programs via audio cable.
However, the video output is VGA and HDMI. VGA output uses 720x576p on 50Hz, horizontal lines are doubled to emulate ZX Spectrum video resolution. 576 lines is less than 625 PAL lines so I had to reduce bottom border to 48 lines instead of original 56.
HDMI is still in progress.
Note that almost everything Spectrum-specific is implemented programmatically in rp2350b firmware. In general you have classic Z80 computer with 16K ROM out of 64K 27c512 chip switchable by DIP-switches, 32K static RAM dedicated to Z80 and 16K static RAM shared between rp2350b and Z80. You can write your own ROM and your own rp2350b firmware to implement any kind of a video controller and input/output functionality. For example it may be a good challenge to use all 16K of shared RAM as a video memory and emulate CGA video modes like 320x200 etc. Also there is an expansion connector having all Z80 signals. I used it to connect kempston-like interface for old-style GamePort joystick but it can be used for any external device.
Software sources and KiCAD projects can be found in my git repository https://github.com/kysilv/z80-rp2350b-zx-compatible
The project is in progress. Initially I made several mistakes in schematic and even in PCB so first version of working device doesn't look very nice. KiCAD projects have been fixed but fixed version is not implemented "in metal" yet.
Hardware
(software/firmware description added below)
Current schematic:

The ROM/RAM part is quite simple:

Here is 32K static RAM chip HM62256 and 64K EEPROM 27c512 sliced to 16K banks that can be switched using DIP-switches. /ROMCS signal exposed to an expansion connector and can be overwritten by external device.
Video RAM and rp2350b playing "ULA" role are here:

I've tried to separate "ULA" data bus and CPU data bus by resistors only, same as in original ZX Spectrum and it works perfectly. To separate address bus and RD/WR control signals I used buffers 74ls541 controlled by rp2350 software. After some timings adjustment it works too...
CPU clock signal is generated by rp2350b according to the memory contention scheme and amplified by transistor s9018 identically to the original ZX Spectrum schematic.
CPU RESET is initially controlled by rp2350b GPIO15 during startup but also there is a button for manual reset afterwards.
Connectors j6 KB1 and j7 KB2 are for keyboard. J5 Joystick is for Sinclair joystick 1 which is just parallel to keys 6,7,8,9,0. I intentionally selected some 9-pin d-sub connector footprint to get the pads on PCB and decide later on actual pin mapping for some physical joystick that I don't have yet.
There are two 5V power connectors just for convenience so you can use USB-C or barrel jack whatever power supply you have.
Video outputs VGA and HDMI:

Resistor/diodes networks schematic I found here: https://github.com/fruit-bat/pico-zxspectrum
My initial idea was to automatically detect what connector the monitor is connected to and load corresponding PIO ASM code to support VGA or HDMI. Hopefully it will be possible to detect monitor using ADC of rp2350b. Currently only VGA is implemented.
HDMI is still under investigation.
Couple photos:


I can't recall if black color should be changed by BRIGHT command to grey... If yes, then this is an issue to think and fix..
Cassette/audio interface is probably the worst part of the schematic:

It worth to be completely redesigned, especially speaker "amplifier"...
Some explanations to the schematic:
- J3 jack connector is just a general output connector to be used for cassette recorder or sound amplifier. R59 should allow speaker output signal from EAR bit to go to J3 for external amplifier and speaker.
- J4 jack connector is for smartphone which can be used as a cassette player to load programs or recorder to save programs/games with some recording app.
- Resistor R27 is needed to force smartphone detecting that something is connected to its mic input.
Note that J13 should be connected by wire to J12 to get power for this audio module.
Software
Architecture of the rp2350b software/firmware:

Almost everything is orchestrated by "master clock" generator ran by PIO0 SM0 producing PIO0 INT0 signal at 7MHz. This signal is used by other SMs for synchronization.
Some details:
- UBUS is a signal to disable 74LS541 outputs so rp2350b is taking control of Video RAM address and control bus. It is also used to tell different SMs that the "ULA" reads Video RAM.
- VRAMCS is a signal produced by circuit logic for Chip Select of video ram chip. It is also used by CLK generator to identify if Z80 is trying to access video RAM.
- PIO0 SM1 generates 3.5MHz Z80 clock signal, taking into account UBUS, VRAMCS and Z80 /IORQ and /A0 signals.
- PIO0 SM2 implements respond to Z80 IN FEh command providing Z80 with port keyboard and tape data.
- PIO0 SM3 reacts to Z80 OUT FEh command taking border color and MIC/EAR data.
- PIO1 SM0 and PIO1 SM1 run the same code and generate HSYNC and VSYNC for VGA output and INTs for internal sync
- PIO1 SM2 uses those INTs to identify frame start and active (visible) part of VGA line and produce signals to Z80 INT generator and VGA RGB signals generator.
- PIO1 SM3 produces VGA RGB output taking pixels from FIFO.
- DMA feeds PIO1 SM3 FIFO from video buffer and border color memory cell.
- PIO2 SM0 is triggered by active frame detector and produces Z80 INT signal as well as triggers Video RAM reading process.
- PIO2 SM1 is triggered by SM0 and orchestrate video frame reading from RAM line by line.
- PIO2 SM2 is triggered by SM1 and control reading one line of video data from physical RAM byte by byte.
- PIO2 SM3 is triggered by SM2 to read one byte from the physical RAM. It takes the byte address from FIFO and put the data byte back to FIFO.
- ARM Core 1 C-code feeds SM3 with Video RAM addresses to read pixel and attributes data and decodes the data to fill "1 byte per RGB pixel" video buffer accordingly. It also implements character flashing function depending on flash bit in attribute byte.
- ARM Core 0 C-code is used to configure DMA and PIO SM code and then hangs up forever. It also handles DMA interrupt.
Vlad