How does reading from a peripheral device at a specific address using SPI work?
The simple answer is hardware. The spi flash and peripheral chips have specific hardware that can work bit by bit and utilise the time a spi clock takes to read the data in time for the next clock to send it out.
On a microcontroller you have a generic spi peripheral that usually works at the byte level - you have to wait until the master spi has clocked 8 bits into the slave. The slave then probably interrupts the cpu. You ‘ve then got interrupt latency and other delays until your spi code runs, figures out what it needs to do and prepare the response to reply. If you have a fast microcontroller and a relatively slow spi clock then you may be able to do everything in time for an ‘immediate’ response to the master. This is usually not the case, so you need to use some form of handshake or a difference method of access whereby you send a command and that primes the next response so you can load up the dma controller to respond immediately to the next command.
In short, implementing a spi slave on a microcontroller is tricky. Having it emulate a serial flash/ram/fram is even trickier. An fpga comes in handy here.