Changes

Jump to navigation Jump to search
no edit summary
:''See also: [http://en.wikipedia.org/wiki/Code_monkey code monkey]''

== Some basics ==

Now we lay down some actual code. First things first: comments! If you've ever done any programming, you know how wonderful comments are. If you've not done much coding, then remember that comments are not as pointless as they seem. Add descriptive comments or be murdered in your sleep 15 years from now by an irate engineer who has to decipher your legacy code. VHDL has no block comments, only line comments (the comment goes from the comment marker to the end of the line). The comment marker is a double dash with no spacing between them. Many development environments (for example Xilinx ISE) will auto-generate a large block of comments at the top of each file to be used to describe the file (who, what, where, when, why, how, and so on).

Secondly are the libraries. These are like the include statements in C/C++. Honestly I forget which libraries have exactly what tools in them, but a standard block will cover mostly any design you work on:

<pre>
-- Lines beginning with "--" are comments
-- This standard block will cover you for most designs.
-- Some development environments will auto-generate library "use" statements that may or may not include this set
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
</pre>

== Coding your black box ==

Every VHDL file defines an '''entity'''. Every entity has two parts to it: a ''port list'' and an ''architecture''. The port list defines the black box of your component. First you declare that you are defining an entity, then inside the entity you declare your ports.

As discussed above, there are three types of ports: in, out, inout. There are also lines and buses. A line is referred to as a '''STD_LOGIC''' and a bus is referred to as a '''STD_LOGIC_VECTOR'''. There are also two flavors of STD_LOGIC_VECTORS: '''downto''' and '''to'''. A "downto" bus has the most significant bit (MSB) associated with the largest subscript, and a "to" bus has the least significant bit (LSB) associated with the largest subscript. A bus with N lines need not have subscripts running from 0 ''to'' N-1. They can run from 1 ''to'' N or N+84 ''downto'' 85; there is complete freedom as to the subscript offset. Most people who learned coding in C or Java or something similar will generally stick to 0 ''to'' N-1 or N-1 ''downto'' 0 out of habit unless the situation calls for something else (for clarity, usually). Often an engineer will choose either "to" or "downto" (I happen to prefer "downto") and stick with it. However mixing "to" and "downto" has it's uses; for example connecting a "downto" to a "to" will reverse the order of the bits in the bus. For a beginner, I recommend picking one and sticking to it.

<pre>
entity component_name is
Port ( line_in : in STD_LOGIC; -- a single input line
bus_in1 : in STD_LOGIC_VECTOR (7 downto 2); -- a 6-bit "downto" input bus
bus_in2 : in STD_LOGIC_VECTOR (0 to 8); -- a 9-bit "to" input bus
line_out : out STD_LOGIC; -- a single output line
bus_inout : inout STD_LOGIC_VECTOR (1 to 10) -- a 10-bit bidirectional bus
);
end component_name;
</pre>

Note that each port in the list is separated by a semicolon, but the last port does not have a semicolon after it. The semicolons in this case are not end-of-line markers, but are list delimiters.

== Example: coding your black box ==

The library use statements and port list for the DAC emulator are shown here. Note the terribly non descriptive comments for the input lines. This kind of comment is not only useless (as it merely repeats the signal name), but is mocking the pain of later engineers who have to figure out what a signal like ''invSYNC'' might do. This will result in ninjas attacking your home. To avoid this fate, I recommend better comments such as, "an active-low flag to begin transmission," for ''invSYNC'' or, "serial clock line," for ''SCLK''.

<pre>
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity DAC_emulator is
Port ( SCLK : in STD_LOGIC; -- SCLK
invRESET : in STD_LOGIC; -- /RESET
invSYNC : in STD_LOGIC; -- /SYNC
D_in : in STD_LOGIC; -- D_in
-- 32 14-bit output channels
ch00 : out STD_LOGIC_VECTOR (13 downto 0);
ch01 : out STD_LOGIC_VECTOR (13 downto 0);
ch02 : out STD_LOGIC_VECTOR (13 downto 0);
ch03 : out STD_LOGIC_VECTOR (13 downto 0);
ch04 : out STD_LOGIC_VECTOR (13 downto 0);
ch05 : out STD_LOGIC_VECTOR (13 downto 0);
ch06 : out STD_LOGIC_VECTOR (13 downto 0);
ch07 : out STD_LOGIC_VECTOR (13 downto 0);
ch08 : out STD_LOGIC_VECTOR (13 downto 0);
ch09 : out STD_LOGIC_VECTOR (13 downto 0);
ch10 : out STD_LOGIC_VECTOR (13 downto 0);
ch11 : out STD_LOGIC_VECTOR (13 downto 0);
ch12 : out STD_LOGIC_VECTOR (13 downto 0);
ch13 : out STD_LOGIC_VECTOR (13 downto 0);
ch14 : out STD_LOGIC_VECTOR (13 downto 0);
ch15 : out STD_LOGIC_VECTOR (13 downto 0);
ch16 : out STD_LOGIC_VECTOR (13 downto 0);
ch17 : out STD_LOGIC_VECTOR (13 downto 0);
ch18 : out STD_LOGIC_VECTOR (13 downto 0);
ch19 : out STD_LOGIC_VECTOR (13 downto 0);
ch20 : out STD_LOGIC_VECTOR (13 downto 0);
ch21 : out STD_LOGIC_VECTOR (13 downto 0);
ch22 : out STD_LOGIC_VECTOR (13 downto 0);
ch23 : out STD_LOGIC_VECTOR (13 downto 0);
ch24 : out STD_LOGIC_VECTOR (13 downto 0);
ch25 : out STD_LOGIC_VECTOR (13 downto 0);
ch26 : out STD_LOGIC_VECTOR (13 downto 0);
ch27 : out STD_LOGIC_VECTOR (13 downto 0);
ch28 : out STD_LOGIC_VECTOR (13 downto 0);
ch29 : out STD_LOGIC_VECTOR (13 downto 0);
ch30 : out STD_LOGIC_VECTOR (13 downto 0);
ch31 : out STD_LOGIC_VECTOR (13 downto 0)
);
end DAC_emulator;
</pre>

== Filling the black box ==

Now that you have your black box, you need to fill it in. The interior of the box is called the '''architecture'''. First you declare that you are making an architecture and what it is an architecture of. Then inside of there you have two sections: declaring your components, signals, and variables, and the actual control flow of the circuit.

Declarations come in three types (that I know of; there may be more):
* '''Components''' are other blocks that you are including in your circuit. Inside of a component is another circuit, which may contain still further components.
* '''Signals''' are internal signals. They are the wires connecting all of your components. As with pins they come in STD_LOGIC and STD_LOGIC_VECTOR, but they do not have I/O polarity as they are strictly internal. As a general rule you attach a signal to a pin so that you can either read from or write to that signal.
* '''Variables''' are like variables in a normal software language. They can only be used inside of a ''process'' (which I will discuss later). Often in simple designs you can work around using variables and stick with just signals. Unfortunately, you'll have to do a bit of online research to find out much detail about variables, as I hardly use them in these designs.
Components and signals should all be declared up front in the declaration section. As I mentioned, you can only use a variable inside of a process, so you would declare the variable within the process.

The framework for the architecture is shown here.

<pre>
architecture arch_name of component_name is
signal line_sig : STD_LOGIC; -- an internal signal line
signal bus_sig : STD_LOGIC_VECTOR (4 downto 2); -- a 3-bit internal signal bus
begin
--------------------
-- code goes here --
--------------------
end arch_name;
</pre>

As you can see, declarations happen before the "begin" and code goes after the "begin". Even if you have no signals, components, or variables to declare, you must include the "begin" statement.

You may have noticed that I did not show a component. Components require more discussion and will be demonstrated later. Because the DAC emulator uses components, I will discuss that code later. First we will discuss the components inside of the emulator and the final product will come later.
461

edits

Navigation menu