18
\$\begingroup\$

I'm currently in the process of designing a simple CPU in VHDL using Xilinx ISE and ISIM. The design portion is going remarkably well, but I can't seem to figure out a way to do verification in a consistent manner.

Right now I have a VHDL test bench that I update to test the function I'm working on at any particular moment. This is very ad-hoc, and it does not help me to catch regressions and cannot be used to verify compliance with specification/instruction set.

I've thought about developing an extensive test suite, but the problem is that the potential state of a general purpose part as a CPU is huge compared less generic components.

I am looking for a method that allows me to perform design and testing in a more controlled manner. Some sort of "hardware TDD" if you will. Does such a thing exist? Can it be applies relatively easily to general purpose parts such as a CPU?

\$\endgroup\$
16
\$\begingroup\$

The whole issue of CPU verification is super large and difficult. There are people who make a career out of just this. I'll just give you the overview...

  1. Write an assembly language program that tests every instruction and every tiny detail of every instruction. For example, when testing the ADD instruction you might test it with numbers that are both positive, both negative, and one of each (twice). You would then test the carry flag, the zero flag, etc. Other special features of the CPU (like branch prediction, etc) would have their own special part of this test.

  2. Write, using C/C++ or something, a model of your CPU. This is your virtual CPU. This is also your "golden CPU", meaning that this is the CPU that everything else is compared to. Ideally the person who wrote the VHDL is NOT the same person who writes the C/C++ model.

  3. Write/Create a system where you can run the C/C++ model and the VHDL model side by side, and compare the results on a cycle-by-cycle basis. Run your assembly program from Step 1 and make sure the two models match.

  4. Run your two models on random "instructions". Basically, fill "ram" with random data and execute that random data as if it is real instructions. Run the same random data on both VHDL and C/C++ models and compare the results. This C/C++ model would run on some workstation and/or server (not the new CPU itself).

  5. Setup a machine, or several machines, to repeat step 4 essentially forever. Even if your CPU is "finished" and has been in production for a year or more you will still be running this test.

  6. Repeat these steps whenever there is more stuff to simulate. For example, you would run it on the post-route VHDL with timing when that's available.

There is no guarantee that comparing the VHDL and C/C++ versions will catch every single bug-- but there really isn't a better way. And testing the CPU on random instructions takes time, but that is also very useful. The only real alternative to this is to hire lots of people to just write code all day to test different parts of the CPU-- and the bigger companies do this, but they also do the random data stuff too.

For a single person writing VHDL code, usually it is just step #1 that is done. But if you are going to sell the CPU then at least some of the other steps should be done (and really, you should do them all).

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Excellent answer, thank you! This makes a lot of sense. The "Golden CPU" is indeed the missing piece of the puzzle that enables you to do cycle-by-cycle verification when testing. Since this is mostly a toy project, I think I will conform to the first sentence of the last paragraph and do just step #1. But knowing what I ought to be doing is invaluable. \$\endgroup\$ – drxzcl Sep 4 '12 at 7:32
  • \$\begingroup\$ You also can have a golden, but non-cycle-accurate, C++ model which allows it to be much simpler and therefore more likely to be correct - useful for testing ALU functionality for example ("2+2=4 and some flags, I don't care when" rather than "2+2=4 after one tick and the flags after 2 ticks") \$\endgroup\$ – Martin Thompson Sep 5 '12 at 9:46
  • \$\begingroup\$ Also, run code-coverage (to check you exercised it all) and test-coverage (to check all the tests have been tested for both pas and fail) \$\endgroup\$ – Martin Thompson Sep 5 '12 at 9:47
  • \$\begingroup\$ Follow-up: Using the "step one" procedure, I managed to find a lot of faults ... in my assembler :P The core itself seems to be relatively ok. \$\endgroup\$ – drxzcl Sep 11 '12 at 9:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.