Let me be the first to tell you -- FPGAs are different than microcontrollers (MCUs). Yes. I know it's shocking to hear this, but whether you want to believe it or not, it's true. (Note: I'm telling this to myself, I'm not talking to folks who know how to use FPGAs.)
Learning how to program, configure, and use FPGAs has been pretty much as different as anything I've ever done. There are, of course, some commonalities, such as the fact I use a keyboard when I'm writing Verilog code, just like I do when I'm writing in a computer language. Also, FPGAs and MCUs are both made out of some sort of silicon type material. Aside from those two attributes, however, I have to say that there's very little in common between MCUs and FPGAs.
This current mini-series on using on-chip RAM in the FPGA has brought this point home better than anything since... well... since the last mini-series I wrote before this one. I'd sure like to thank everyone who's read and commented on the various topics and concepts. I hope the discussions have been enlightening to other rookies here -- and not just enlightening in terms of how thick my skull can be, but also in terms of how to use these programmable logic thingies.
My on-chip RAM project isn't complete, but -- with all of the bludgeoning I've been doing -- this seems like a good time to pause and reflect a bit on what I've learned and what, hopefully, other people will learn faster than I did.
I can definitively state that if you have a lot of programming experience and are tempted to draw on that experience when visualizing FPGA concepts -- Stop! Don't do it! While both MCUs and FPGAs are electronic components, and both have IDEs (integrated development environments), creating something to stuff inside them is far too different to make any such comparisons useful.
I'll illustrate where my software thinking has gotten me into trouble. It started with a comment about delay between addressing the RAM and data availability. In this particular case, the specific syntax sent me down the wrong path.
As you may recall, my RAM block is inferred using the following syntax:
Next, I have an 8-bit register that will take the byte from RAM to be shifted out to the MOSI line in my SPI interface:
I also have an address register that I define as such:
At a later point, down in my SPI code, in my "always" block, I set the address register to a RAM address I want to read. That would be this line:
In this case, "address_ptr" is just another 11-bit register that I manipulate. It's probably redundant, but it's there, and in the above line, "address_ptr" is used to load the desired address into "address_reg." Next, I read the RAM with the following statement:
When we started discussing a delay between presenting the address to the RAM and reading the data out of the RAM, my thought process went full-on non sequitur. I was -- and this is the important part for any software folks reading this -- thinking about "ram_block[address_reg];" as though it were a software array with "address_reg" being a variable/pointer. Thinking that way will seriously mess you up.
The correct understanding is as follows: When Verilog (or VHDL) sees the statement "ram_block[address_reg];", it essentially wires up hardware around "address_reg" and "ram_block." The FPGA has the connection between these two objects in it from the moment it's configured with a bitstream.
My software brain had me thinking as though "address_reg" was a variable holding some data, and that this data wouldn't be at all connected to the RAM until used to address "ram_block." That is not the case; "address_reg" is not a variable. It's more like a label attached to a register that is hard-wired to the address lines of the RAM block. This is important.
At any point in my Verilog code, regardless of the line number relative to any portion of the code, whatever value is loaded into "address_reg" is immediately presented to the addressing logic of the RAM block.
Some time ago I added "It's not an array, it's a ribbon cable" into my list of mantras. Now I've added "It's not a variable, it's the name of a register" onto that list.
For any other FPGA rookies, what sorts of traps have hit you the hardest? And for you seasoned veterans, do you recall what really killed you back in the days when you were new to programmable logic?