in HDL, some parts of the code can work at the same time, for example two lines of code "can work" at the same time, this is an advantage, to use wisely.
this is something that a programmer who is accustomed to line by line languages may find hard to grasp at first:
- Long and specific for your needs pipelines can be created.
- You can make your big modules work at the same time.
- instead of one unit to do a repeated action on different data, you can create several units, and do the work in parallel.
Special attention should be given to the booting process - once your chip is functional, you have made a huge way.
Debugging on hardware is usually much harder than debugging software so:
Simple code is preferred, sometimes there are other ways to speed-up your code, after
it is already running, for example using an higher speed chip, etc'.
Avoid "smart" protocols between components.
A working code in HDL is more precious than on other software, as hardware is so hard to debug, so reuse, and also consider using "libraries" of modules which some are free and others sold.
designing should consider not only bugs in the HDL code, but also failures on the chip you are programming, and on other hardware devices that interface with the chip, so one should really think about a design that is easy to check.
Some debugging tips:
If a design includes several building blocks, one would probably want to create lines from the interfaces between those blocks to testing points outside the chip.
You will want to save enough lines in your design to divert interesting data to be inspected with external devices. also you can use this lines, and your code as a way of telling you the current state of execution - for example if you receive data at some
point, you write some value to the lines, at a later stage of execution you write another value, etc'
If your chip is reconfigurable this will become even more handy, as you can tailor specific tests, and reprogram the outputs for each test as you go (this looks very well with leds :). )
Edit:
By smart protocols, I've meant that should two of your physical units connect, they should communicate with the simplest communication protocol available. that is, do not use any sophisticated home-made protocols, between them.
The reason, is this -
Fidning bugs "inside" an FPGA/ASIC is reletivly easy as you have simulators.
So if you are sure that data comes as you want it, and goes out as your program sends it,
you've reached Hardware utopia - being able to work at software level :) (with the simulator).
But if your data doesn't get to you, the way you want it to, and you have to figure out why... you'll have to connect to the lines, and that's not that easy.
Finding a bug on the lines, is hard as you have to connect to the lines with special equipment, that record the states of the lines, on different times, and you'll have to make sure your lines act according to the protocol.
If you need to connect two of your physical units make the "protocol" as simple as it can , up to the point it won't be called a protocol :)
For example if the units share a clock, add x data lines between them, and make one unit write those and the other unit read, thus passing one "word" which has x bits between them on each clock fall, for example.
If you have FPGA's, should the original clock rate be too fast for parallel data - you can control the speed of this, according to your experiments, for example making the data stay on lines of at least 't' clock cycles etc'.
I assume parallel data transfer is simpler, as you can work with at lower clock rates and get the same performances, without the need to split your words on one unit, and reassemble on the other. (hopefully there is no delay between the 'clock' each unit receives).
Even this is probably too complex :)
Regarding SPI, I2C etc' I haven't implemented any of them,
I can say that I've connected legs of two FPGA's running from the same clock, (don't remember the exact formation of resistors in the middle), at much higher rates, so I really can't think of a good reason to use those, as the main way to pass data between your own FPGA's, unless the FPGA's are located very far one from another, which is one reason to use a serial rather than a parallel bus.
JTAG is used by some FPGA companies, to test/program their products, but not sure if it's used as way to transport data at high speeds, and It is a protocol... (still one which may have some built-in on chip support).
If you do have to implement any known protocol, consider using a pre-made HDL code for this - which can be found or purchased.