As the title suggest, my intention was to originally write about QSPI only, but I would not have likely written about it when everything worked as intended, but as we already know, things are never that simple and the world is just cruel from the designer’s perspective.
It all started when I wanted to reuse a block of code at my project – Just a standard SPI communication interface to external Micron flash memory. Thing that must have been programmed million times across the globe for the SPI time being. The interface is pretty old, so one might be tempted to say that controller such as this would have the best code base and documentation. But as noted, life is never that beautiful and I started to wonder whether using a vendor-provided IP might not be a better alternative to improve the code base (Because I was obviously lazy to dig into SPI myself and code the entire interface from beginning). So I looked up the Xilinx AXI Quad SPI IP (PG153) and started to read how to incorporate this IP into the project. First of all, even though I personally consider the Xilinx documentation very accurate, there are obviously some reserves and PG153 is one of those exceptions. Unfortunately for me, I wanted to start with the most simple communication scheme (Excluding XIP – “Execute In Place” and generally more complex SPI configurations), but since the IP is intended for general use, there is simply a lot of configuration and documentation that takes effect only when the IP is used in this or that mode not to mention that one needs to talk for example through the STARTUPE3 primitive block, which itself kind of lack documentation.
I think the overall Idea after reading the sheet was really to use it with a soft-core processor because using standard CPU accesses over PCIe would kill the entire interface due to huge amount of register accesses required to manage the interface. So I was playing around for a while with this IP (Happy that I was able to read the 32-bit Micron Flash identification code) … And then slowly started to rethink that in the end, it might be a good idea to just start over, select a few commands that would allow me to read, program and erase the flash and then code the interface myself from the beginning. This idea came into reality when I realized that the Xilinx AXI QSPI IP is not encrypted and that there are tons of files where I can look how the engineers at Xilinx have coded this IP.
My eyes couldn’t however believe such a mess in the Xilinx code base. It was really awful. Unstructured, unclear, old comments and headers, plenty of commented out code occasionally interlaced with hexa numbers without explanations etc. I have seen already a lot ( In fact really quite a lot ! ) of bad code and unfortunately I had to extend my list of encountered bad codes by the underlying AXI Quad SPI IP codebase. Sometimes I think that its really a miracle that things around us at least somehow works (Even though you have to occasionally reboot or reset them … ). I think the overall problem is that people responsible for the management of the project / development are usually out-of reality of what needs to be done and what are the real problems and obstacles, so it boils down to the engineer who is constantly pissed of by the fact that nobody listens to him that “Its really not that simple to incorporate this into that and that its really not just ctrl+c / ctrl+v as some managers think for example – yes I have heard that myself several times, its really not a funny thing! “.
Anyway, since I have already previously had some good experiences at least with simulation of PCIe and or DDR4 interfaces (With Xilinx’s IPs), I wanted to download the Micron QSPI flash model, write the testbench and then execute a few read/program/erase operations. I dont know if I had felt surprised when the overall structure of verilog model was in approximately the same shape as in the case of the Xilinx’s QSPI IP. But then I said, ok, lets see how it does and I have initiated a few commands in the simulator.The first surprise was that the model transmitted a different ID than it was supposed to … but okay, who really cares about ID especially when its some model for the public and just simulation? So I went down to programming the flash. I really dont know who had the idea of reporting the same value in 2 different flash registers (QSPI Flag status and QSPI Status registers) but the model complained that I should read only one of those eventhough the documentation says that I can read any of those. Okay, who cares again? I have seen too many documentation errors already, so I wasn’t surprised by this complaint at all. I switched the register to the other one and waited for erase / programming completion in that register. What a surprise when I read in the console that controller is finally done, ready to receive new commands – which thereafter reports that the controller is unable to handle those request because it is still busy! I spent some time figuring out whether its really me who is so stupid or whether the code base is really another waste of time and resources …
At this point, I have to note that I felt quite angry. The solution was pretty clear though – Lets write our own QSPI model! If you think that writing an entire QSPI model is hard, I might be nowadays tempted to say now that no – its not that hard especially if you know that you need to support only a limited set of functions and commands. The only problem for me is that I am FPGA designer and I do not have that much practise with ASIC design (Never say never) – nevertheless, VHDL and a few more hours at PC provided a model, which works as intended in the simulator – Can store incomming data and send them back over SPI. Receive commands such as Read / Program / Erase and even report correct ID (And whats more the SPI interface then really works in hardware)!
What a “masterpiece” – Yet only on a few lines of code 🙂
BTW: AXI4 Package is my own internal package (Obviously for AXI Testing).
There is nothing useful for this model in this package. Just declare the following:
- subtype sl is std_logic;
- subtype slv is std_logic_vector;