If you, like me, are coming from AVR/Arduinoland this may your thought process when you get an FPGA Devboard:
- There are some blinkenlights on there, how do I make them blinken
- OK, I guess there are things that look like variables that I can tie to pins
- how do I do that?
If you are already an FPGA designer then before you complain that I’m getting everything wrong, realize I’m writing this as I learn. Part of this is to document the failings when first switching from C on a uC to VHDL on an FPGA.
Instead of writing a function in VHDL you write a module, that contains an entity. You can think of this as a tiny little IC that you are making inside the FPGA. You might have a shift register entity, or a uart, or a multiplexer. Each of these can have ports, that define the inputs and outputs of the entity. That would be like the pins of the IC you are designing. If you want to link those to actual pins of the device, that’s where the “constraints file” comes it. Using the constraints file you can define names that refer to actual pins on the package.
Where do I get a constraints file
Well, you could pore over the datasheet of your FPGA, and the dev board, and then write one. But if you have a devboard chances are there is one available. For the nexys 2 it’s here: https://reference.digilentinc.com/reference/programmable-logic/nexys-2/start.
Here is a block of text from it:
##7 segment display #NET "seg<0>" LOC = "L18"; # Bank = 1, Pin name = IO_L10P_1, Type = I/O, Sch name = CA #NET "seg<1>" LOC = "F18"; # Bank = 1, Pin name = IO_L19P_1, Type = I/O, Sch name = CB #NET "seg<2>" LOC = "D17"; # Bank = 1, Pin name = IO_L23P_1/HDC, Type = DUAL, Sch name = CC #NET "seg<3>" LOC = "D16"; # Bank = 1, Pin name = IO_L23N_1/LDC0, Type = DUAL, Sch name = CD #NET "seg<4>" LOC = "G14"; # Bank = 1, Pin name = IO_L20P_1, Type = I/O, Sch name = CE #NET "seg<5>" LOC = "J17"; # Bank = 1, Pin name = IO_L13P_1/A6/RHCLK4/IRDY1, Type = RHCLK/DUAL, Sch name = CF #NET "seg<6>" LOC = "H14"; # Bank = 1, Pin name = IO_L17P_1, Type = I/O, Sch name = CG #NET "dp" LOC = "C17"; # Bank = 1, Pin name = IO_L24N_1/LDC2, Type = DUAL,
You can see they did most of the hard work of finding the pins and providing comments that are useful. # and // both mean a line is commented out. If you uncomment a line, you MUST use that signal in your VHDL file. So you only uncomment the signals you need to physically bring out. Then when you have an uncommented line it might look like
NET “Led<0>” LOC = “J14”;
That means when you assign a value to LED(0) it will bring that out as a voltage on pin J14.
Part of the reason FPGAs are so flexible is that you can redefine these at will. Say you had a new board and you wanted to bring out the pin somewhere else to make routing easier, you could.