"Hello World" equivalent for hardware engineers

I was staring out my office window at some towering Douglas fir trees, trying to figure out how to introduce non-DSP hardware engineers to how cool C synthesis is.  Okay, I did say engineers since a majority of people would not find anything to do with C or synthesis cool.  I’m sure I’d get a lot more Google hits on my blog if I talked about the Dallas Cowboys or the Portland Trailblazers, my big interests outside of work and family.

Anyway, back to my dilemma.  The first adopters of C synthesis have been mostly DSP gurus developing wireless or video hardware, so you see a lot of FIR filter demos that show how you can get lots of different implementations from the same C code simply by adjusting the loop constraints for latency and throughput.  What about someone coming from a pure RTL background that is writing non-DSP ASIC or FPGA hardware.  How can I show them something quick and easy that anyone can try?

Preparing Recommendations

I drifted back to when I was first starting at Lattice Semiconductor in the mid-90s.  VHDL was just making its way into programmable logic.  Schematics were losing out to ABEL for the simple PLDs, but the CPLD and FPGA devices needed something more abstract.  Yeah, I know, I’m dating myself.  Anyway, our basic training for new field application engineers was based around building a clock dividing counter and driving some seven segment LEDs on a demo board.  There, I have it.  The first test of a hardware synthesis tool is to make some LEDs blink on a demo board.  This would be the equivalent of writing C code to print out “Hello World” for the first time coder.

As a second check, one of my standard questions during job interviews to get a baseline for someone’s hardware knowledge was to have them design a simple binary up counter with asynchronous reset.  That’s about as basic a hardware problem as you can get, but it uncovered whether someone understood synthesis or just the language semantics.  Of course, if you didn’t write VHDL everyday, remembering the library use statements with the standard IEEE synthesis libraries was hard to fake.  Modeling the reset and clock with the proper sensitivity list was pretty straightforward.  However, the counter registers were read and written, so the common mistake of declaring them as outputs on the interface caused an error unless you used internal signals.  I expected them to write something like:

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;

ENTITY cnt IS
        PORT (
                clk     : IN            STD_LOGIC;
                rst     : IN            STD_LOGIC;
                qout : OUT      STD_LOGIC);
END cnt;

ARCHITECTURE rtl OF cnt IS
        SIGNAL  cnt_reg : STD_LOGIC_VECTOR(15 downto 0);
BEGIN
        PROCESS (clk, rst)
        BEGIN
                IF rst = ‘0′ THEN
                        cnt_reg <= (others => ‘0′);
                ELSIF (rising_edge(clk)) THEN
                        cnt_reg <= cnt_reg + ‘1′;
                END IF;
        END PROCESS;
                       
        qout <= cnt_reg(15);
       
END rtl;
 

Now, you can pass that part of the interview, but I digress.  Back to using C for hardware design…  I happened to have an older Altera NIOS II Development Kit with a Stratix II FPGA, some LEDs and buttons on it.  After downloading the correct reference manual, I had pinouts for the devices on the board.  You have to love the new BlackBerry Pearl with built in camera for stuff just like this blog.

Altera NIOS II board

This should be pretty easy to do.  The crystal oscillator is running at 50MHz, so I decided to blink an LED every second with a 50/50 duty cycle.  The first step is to write a C program to do this function.  Basically, I just want to toggle the LED value every 25M clock cycles to have it blink once per second (on for half a second, off for half a second).

#define MAX_COUNT 50000000
bool clk_div()
{
        static bool toggle_val=false;

        for (int i=0; i         {
                if (i==MAX_COUNT/2-1)
                        toggle_val = !toggle_val;
        }
        return toggle_val;
}

The static statement creates the register that will drive the LED.  This program will compile with any C compiler.  On Windows, I use the free Microsoft Visual C++ Express version.  On Linux, gcc is most common.

A simple testbench will show that it is working in the debugger:

#include
bool clk_div();

int main()
{
        printf(”Starting clock divider\n”);
        for (int i=0; i<9; i++)
        {
            printf(”Clock value = %i\n”, clk_div());
        }
        return 0;
}

Screen capture of test

Now, I’m ready to synthesize this down to the board and see if it works as I expect.  A common question that comes up from hardware designers is “how do I control the size of the registers?”  Remember, the VHDL for the counter defined std_logic and std_logic_vector types.  In this case, the static bool toggle can obviously be implemented as a single bit.  The loop counter “i” needs to hold MAX_COUNT/2-1, so for the 50MHz clock, this is a 25-bit unsigned number.  The standard C int data type is at least 32-bits, so it can hold this number, but I can model this exactly in C and test it using the Mentor Graphics Algorithmic Datatypes, a free download from http://www.mentor.com/products/esl/high_level_synthesis/ac_datatypes.

By replacing the definition of the loop variable to a uint25, I’m guaranteed to use a 25-bit unsigned number and see that it still works.  Better yet, I can try a uint24 and see that the loop never makes it to MAX_COUNT/2-1.  I just have to include “ac_int.h” and change the for loop to:

for (uint25 i=0; i

To synthesize this design, I bring up Catapult C Synthesis, add the input file to the project, set up the clock at 50MHz, enable active low asynchronous reset and set the technology to an Altera EP2S60F672C-3.  To tell Catapult that I want this design to be free running, I pipeline the top-level design with an initiation interval of 1 (II=1).  Then, I generate RTL (VHDL or Verilog).  After running through Precision RTL and Altera Quartus, I have a bitstream I can program onto the board.

Voila – I have a blinking LED and reset from a push button.  If you have QuickTime, you can watch the 8 second video I took, again with my BlackBerry, of my board blinking (blinking_led.3GP).  Unfortunately, I can’t seem to include the video as an attachment in this post.  Here’s link to it on YouTube, http://www.youtube.com/watch?v=mNKEvC8P3Zc.

Thanks for reading.  Comments and questions welcome.

Dan

About Dan Gardner

imageDan Gardner is a technical marketing engineer at Mentor Graphics on the high-level synthesis team. He is an experienced RTL hardware design engineer with both ASIC and FPGA experience. Visit Dan Gardner's Blog

More Posts by Dan Gardner

More Blog Posts

Preparing Recommendations

Comments (↓ Add Your Own)

12 Comments on this Post

Commented on 10:57 PM, Jul 8, 2009
By Din

Dan, thanks for writing this up. My own background is in standard C programming (for Windows, x86 etc.), so I'm very familiar with the proverbial "Hello World". In fact, I'm trying to teach this to my own pre-teen kids. However, I like your take on "Hello World" for hardware and applying C-based design - a basic implementation but very important to see if you are communicating properly with the hardware, much less programming it correctly. This is an excellent introduction, and I hope to see more posts in the near future.

Commented on 4:14 PM, Jul 15, 2009
By Vova

It seems to me, that HTML parser eat tags at line: for (uint 25 i=0; i

Commented on 12:36 AM, Jul 16, 2009
By Dan Gardner

Hi Vova, I'm not sure you completed your comment. Please clarify and I'll gladly respond.
[...] my first blog attempt about blinking an LED on a demo board seemed to generate some amount of interest from a few [...]
[...] His posts have detailed source code, both in C and RTL. In his first post, Dan takes a simple clock dividing counter all the way from C to FPGA. This post is a very valuable reading and a great practical introduction to C [...]

Commented on 5:38 PM, Oct 1, 2009
By Cpr

good example, but it would be good to explain why the for-loop in the example is done with the if statement inside it. A usual programmer would just have the for-loop with empty statement and toggle_val inversion as a separate statement. Does it have something to do with parallelizm and how to control it? Also, its a bit bad example to require designer still to optimize variables at bit level while the compiler could do that. It's high level synthesis after all..

Commented on 11:46 PM, Oct 1, 2009
By Dan Gardner

Thanks for the comments Cpr. The reason I had to put the if inside the for is that a simple delay loop will be optimized away by a synthesis tool since there is no concept of time. As you aluded to, I originally had the if outside the for loop, but I didn't get the delay counter. By moving the if inside, the counter was built. Catapult will automatically optimize the index to the number of bits it needs, but I was playing with bit-accurate data types. You are right that it is not necessary, but otherwise it just looked like software. :)

Commented on 10:37 PM, Feb 17, 2010
By Janarbek Matai

Hi Dan, I am also newbie to HW world. I am C/C++ programmer. I have Catapult tool( University version) and FPGA virtex 4 board. I want to run simple blinking like yours. I have modified your code as below. Because the original code didn't worked because Catapult found an error in For loop. Now, I have successfully generated verilog and VHDL but it does not work on FPGA. Do you have any idea? #pragma hls_design top #define MAX_COUNT 50000000 bool clk_div() { static bool toggle_val=false; for (int i=0; i<100000;i++) { if (i==MAX_COUNT/2-1) toggle_val = !toggle_val; } return toggle_val; } #include int main() { printf("Starting clock divider\n"); for (int i=0; i<9; i++) { printf("Clock value = %i\n", clk_div()); } return 0; }

Commented on 11:54 PM, Feb 17, 2010
By Janarbek Matai

I have successfully run your code on Catapult, but still it is not working on FPGA Virtex 4.

Commented on 12:11 AM, Feb 18, 2010
By Dan Gardner

Hi Janarbek, What was the error message you had from Catapult? It looks like you have dropped the for loop iteration count below MAX_COUNT/2, so the signal will never toggle. Using the SCVerify flow, you can check the output waveforms in Questa to see if you get a 50/50 duty cycle output signal. Be careful what you pick for MAX_COUNT. What is the clock speed on your Virtex 4 demo board because you'll need to divide that clock down enough so you can see the LED blinking. Dan

Commented on 2:02 AM, Feb 20, 2010
By Janarbek Matai

Hi Dan, I have tried your example on Catapult. And done till Verify stage. How can I upload the generated VHDL to FPGA? I have used Xilinx ISE but not succeded.

Commented on 11:53 PM, Feb 20, 2010
By Dan Gardner

What do you mean by "not succeeded"? Were you able to get through RTL synthesis? The only supported FPGA synthesis is Precision, but you may have run the RTL directly through ISE synthesis. You should have access to Precision through the univesity program, then you can run a gate level simulation with the Catapult integrated flow as well. If ISE is able the place and route the design without problems, check the pins outs to make sure you the CLK and RST (check polarity of RST) hooked up correctly. If you aren't familiar with HW design, this can be confusing at first.

Add Your Comment

Please complete the following information to comment or sign in.

(Your email will not be published)