Changes

Jump to navigation Jump to search
6,025 bytes added ,  18:34, 6 July 2007
no edit summary
Line 252: Line 252:  
The most significant bit of the ''Q'' bus flows from the logical AND of line ''D'' and all lines in bus ''S''.  Pretty simple, right?  There is an order of operations to VHDL (feel free to run a Google search), but you can enforce your own ordering through the use of parentheses.
 
The most significant bit of the ''Q'' bus flows from the logical AND of line ''D'' and all lines in bus ''S''.  Pretty simple, right?  There is an order of operations to VHDL (feel free to run a Google search), but you can enforce your own ordering through the use of parentheses.
    +
Any questions?  Hopefully not, because we're moving on.
 +
 +
=== The next step: sequential logic ===
 +
 +
Now we're moving into the realm of sequential logic.  As you may recall, that means we're adding a clock.  This is also where you usually add conditional statements (if, case, etc) and loops (for, etc).  So we get to add a new idea: the '''process'''.  I mentioned processes before, because that's where variables live.  Any time you have conditional statements or loops, they must be enclosed within a process.  A process tells VHDL that some signal(s) need to be watched and that this block needs to be updated if those signals change.  The list of signals to watch is called the "process sensitivity list".  Like an architecture, a process has a framework (giving it a name and a sensitivity list), a declaration region, and a code region.  Let's look at the code for the shift register in our emulator:
 +
 +
<pre>
 +
library IEEE;
 +
use IEEE.STD_LOGIC_1164.ALL;
 +
use IEEE.STD_LOGIC_ARITH.ALL;
 +
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 +
 +
entity DAC_shifter is
 +
    Port ( SCLK     : in  STD_LOGIC; -- clock
 +
          invRESET : in  STD_LOGIC; -- asynchronous, active-low reset
 +
          Enable  : in  STD_LOGIC; -- shift enable
 +
          D_in    : in  STD_LOGIC; -- serial in
 +
          Addr    : out STD_LOGIC_VECTOR (4 downto 0); -- address portion of output (5MSB)
 +
          Code    : out STD_LOGIC_VECTOR (13 downto 0)); -- code portion of output (14LSB)
 +
end DAC_shifter;
 +
 +
architecture DAC_shift_arch of DAC_shifter is
 +
    signal SReg : STD_LOGIC_VECTOR (18 downto 0); -- internal resistor value
 +
    signal delayed : STD_LOGIC;
 +
      -- delay serial input due to delay caused by 19-cycle hold block
 +
begin
 +
    delayer : process (SCLK, D_in, delayed) -- delay serial input
 +
    begin
 +
        if (rising_edge(SCLK)) then
 +
            delayed <= D_in;
 +
        else
 +
            delayed <= delayed;
 +
        end if;
 +
    end process delayer;
 +
 +
    shift_reg : process (SCLK, invRESET, Enable, D_in)
 +
    begin
 +
        if (invRESET = '0') then
 +
            -- asynchronous, active-low reset
 +
            SReg <= "0000000000000000000";
 +
        else
 +
            if (Enable = '1') then
 +
                if (rising_edge(SCLK)) then
 +
                    -- shift up when shift is enabled
 +
                    for i in 0 to 17 loop
 +
                        SReg(i+1) <= SReg(i);
 +
                    end loop;
 +
                    SReg(0) <= delayed;
 +
                else
 +
                    SReg <= SReg;
 +
                end if;
 +
            else
 +
                SReg <= SReg;
 +
            end if;
 +
        end if;
 +
    end process shift_reg;
 +
 +
    Addr <= SReg(18 downto 14); -- split parallel output
 +
    Code <= SReg(13 downto 0);  -- split parallel output
 +
end DAC_shift_arch;
 +
</pre>
 +
 +
So what do we see?  Well, a whole lot.  So let's start small:
 +
 +
<pre>
 +
delayer : process (SCLK, D_in, delayed)  -- delay serial input
 +
begin
 +
    if (rising_edge(SCLK)) then
 +
        delayed <= D_in;
 +
    else
 +
        delayed <= delayed;
 +
    end if;
 +
end process delayer;
 +
</pre>
 +
 +
Okay, now what?  Well, this is a process.  It is called "delayer".  After the name we say it's a process and give the sensitivity list.  That means that if ''SCLK'', ''D_in'', or ''delayed'' changes, then the synthesizer needs to check this process again to see if anything else changes.  We had to put this inside of a process because it makes use of the if-else construction.  You can see the format of the if-else:
 +
 +
<pre>
 +
if (condition) then
 +
    statement_1
 +
else
 +
    statement_2
 +
end if;
 +
</pre>
 +
 +
You also see a shorthand that has been pre-defined for you: rising_edge.  There is also falling_edge.  These combine the ''event'' command with a specification of which direction the event happened (transition up or transition down).  Sequential logic makes extensive use of rising_edge and falling_edge.  Also note the else clause.  What is the point of having ''delayed'' loop back on itself?  This is to help the synthesizer along.  VHDL has some quirks and doesn't appreciate an if without an else.  So even if nothing happens, you always want to put that else clause in there and have all the signals in question loop back on themselves.  Otherwise the synthesizer goes crazy and adds latches left and right which at best make your design hideously large and unwieldy and at worst make your design completely nonfunctional.
 +
 +
Now let's take a look at the second process.
 +
 +
<pre>
 +
shift_reg : process (SCLK, invRESET, Enable, D_in)
 +
begin
 +
    if (invRESET = '0') then
 +
        -- asynchronous, active-low reset
 +
        SReg <= "0000000000000000000";
 +
    else
 +
        if (Enable = '1') then
 +
            if (rising_edge(SCLK)) then
 +
                -- shift up when shift is enabled
 +
                for i in 0 to 17 loop
 +
                    SReg(i+1) <= SReg(i);
 +
                end loop;
 +
                SReg(0) <= delayed;
 +
            else
 +
                SReg <= SReg;
 +
            end if;
 +
        else
 +
            SReg <= SReg;
 +
        end if;
 +
    end if;
 +
end process shift_reg;
 +
</pre>
 +
 +
This one is a little more complicated.  First we see that the ''invRESET'' signal takes effect outside of the rising_edge condition.  That makes it an asynchronous signal; that is, it takes effect instantly instead of waiting for the next clock cycle to happen.  Then inside of the rising_edge condition we see a for loop.  The format of such a loop is
 +
 +
<pre>
 +
for i in a to b loop
 +
    statements
 +
end loop;
 +
</pre>
 +
 +
Here ''i'' is actually a variable (and can be named anything you want it to be named).  However it is a read-only variable, so don't bother trying to write to it.  The bounds of the loop are set by ''a'' and ''b'', which must be static at this point in the program.
 +
 +
So how are you feeling about all of this code?  Take a look at the other components and see if you can figure out what they're doing as some practice:
 +
* '''Add a link to DAC_demux.vhd'''
 +
* '''Add a link to DAC_follow.vhd'''
 +
* '''Add a link to DAC_hold19.vhd'''
 +
* '''Add a link to DAC_shifter.vhd'''
 +
* '''Add a link to DAC_register.vhd'''
     
461

edits

Navigation menu