Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

numbers, numbers...

Being new to VHDL, I must admit I find quite confusing the correct application of the use numbers in VHDL.

For the problem I wish to have help on in my thread here, I have found that my VHDL simulates correctly, but when finally mapped to a 'read' FPGA, the timings are halved. I think it must be down to the way in which I am using and applying numbers perhaps. If I hard code numbers in VHDL it is fine, if a core processor writes these numbers, my outputs go twice as fast.

This works correctly:


Horizontal_proc : process (IN_RESETn, IN_CLK)
begin
  if IN_RESETn = '0' then
    counter_HORIZONTAL_7_0      <= (others=>'0');
     counter_HORIZ_SYNC_WDTH_3_0 <= (others=>'0');
     HS    <= '0';
     Hdisp <= '0';
     
  elsif falling_edge(IN_CLK) then
     --Horizontal TOTAL end? Hdisp Start
     if MAKE_BINARY(counter_HORIZONTAL_7_0) = b"0010_1111" then   --REG_R00_HORIZ_TOTAL_7_0
        counter_HORIZONTAL_7_0 <= (others=>'0');

Twice as fast:


Horizontal_proc : process (IN_RESETn, IN_CLK)
begin
  if IN_RESETn = '0' then
    counter_HORIZONTAL_7_0      <= (others=>'0');
     counter_HORIZ_SYNC_WDTH_3_0 <= (others=>'0');
     HS    <= '0';
     Hdisp <= '0';
     
  elsif falling_edge(IN_CLK) then
     --Horizontal TOTAL end? Hdisp Start
     if MAKE_BINARY(counter_HORIZONTAL_7_0) = REG_R00_HORIZ_TOTAL_7_0 then 
        counter_HORIZONTAL_7_0 <= (others=>'0');
  etc.

I am including:


library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use work.config.all;

The entity I/O's:


entity mythingy is
  port (
     IN_E            : in    STD_LOGIC;
     IN_RS           : in    STD_LOGIC;
     IN_CSn          : in    STD_LOGIC;
     IN_RW           : in    STD_LOGIC;
     IO_D_7_0        : inout STD_LOGIC_VECTOR (7 downto 0);
     IN_RESETn       : in    STD_LOGIC;
     IN_CLK          : in    STD_LOGIC
  );
end mythingy;

That counter & matching 'reset' register above:


  signal REG_R00_HORIZ_TOTAL_7_0 : STD_LOGIC_VECTOR (7 downto 0);  --Horizontal Total
  signal counter_HORIZONTAL_7_0 : UNSIGNED (7  downto 0);

Register 'programmed' thus:


ext_write : process(IN_RESETn, IN_E, IN_CSn, IN_RW, IN_RS)
begin                           
  if IN_RESETn = '0' then        
    REG_R00_HORIZ_TOTAL_7_0  <= b"0010_1111";
  elsif falling_edge(IN_E) and IN_CSn='0' and IN_RW='0' then    --Grab data from data bus and program into indexed register.
    case REG_INDEX_ADDR_4_0 is                                         --Use Reg Index to write D0-7 to reg
      when INDEX_HT => REG_R00_HORIZ_TOTAL_7_0 <= IO_D_7_0;
  
etc

appears OK to me, but I am thinking non-standard libraries or some mis-match of types or skewed binary numbers (right-shifted) and hence the counter stops at half the count I am expecting and hence runs twice as fast when VHDL mapped into an FPGA.

Any useful insights would be much appreciated. Thorough understanding of number systems is VERY important of course!

Cheers,

Andy

17 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Anywho, let me see if I have this right in my tiny brain:

    
    use IEEE.std_logic_1164.all;
    

    defines what various 'standard' states a signal state can be in at any given point in time, i.e. 'Z' 'X' '1' '0' 'W' 'U' 'L' 'H' '-'

    A signal (or vector) can be all of these states, or indeed a subset of these. If using a subset, then depending on what is missing (e.g. 'Z') then the simulation may miss out on telling the user that something 'weird' is going on.

    --- Quote End ---

    Yes but you got the order wrong, it should be U X 0 1 Z W L H -. this is important as all signals initialise to their leftmost state. And 'U' means "Uninitialised", and might tell you you forgot to set an input in your simulation. Also know that VHDL was origionally written to model digital circuits in the early 80s when such things were all done on PCBs, hence weak high 'H', weak low 'L', weak unknown 'W'. 'Z' means high imedance, which is crucial for tri-state ports (they only exist on the physical pins of the device, any internal tri-states will be converted to muxes in an FPGA). Then finally you have 'X' (unknown) which occurs when you drive two busses together, and '-' (dont care) which is actually quite tricky to use, dispite it's name.

    For example, if A = "1111", writing

    if A = "10--" then

    will only work in simulation when A is exactly "10--", so "1011 will not match (but in synthesis, it would make a circuit that wouldnt care). So in the numeric_std library, there is a std_match function:

    if std_match(A, "10--") then

    Would work in both simulation and synthesis.

    W, L, H do not exist in FPGAs, and neither do X, U and -. Anything assigned to these will be replaced with 0 or 1. Like I said before, Z is only used for tri-states.

    --- Quote Start ---

    use ieee.numeric_std.all;

    (snip)

    --- Quote End ---

    You all mostly correct. Not only does it define all those, but it also defines all functions for unsigned and integer types mixed, so

    a <= b + 1;

    c <= b + x"01";

    if x = x"FFFFF1" then

    if x = 10 then

    Will all work just fine. The functions convert the integer to an unsigned thats the same length as the other unsigned, which is also why you can do:

    signal a,b : signed(7 downto 0);

    a <= b + "1";

    Because it makes both b and "1" into 8 bits before adding them, and because it is signed, it will sign extend the second operand for you (the output here is that a is "11111111").

    But be wary - you cannot overload the assignment operator, so you cannot write:

    a <= 10;

    because a is signed and 10 is an integer. So you need to convert the integer to a signed explicity:

    a <= to_signed(10, a'length);

    Also note that it can work out the function to call from just the operands, but it will throw a compile error if it finds multiple options for the same function. The classic example is the write function from textio when you're writing a string, as anything in double quotes could be a string or a bit_vector (or a std_logic_vector, unsigned or signed if you're using VHDL 2008), so you need to qualify what you want with the '

    write(op, string'("hello world!"));

    So, going back to your question about "logic comparision"

    if a = "10101010" then

    will always know that you meant "10101010" as a signed, as there is no function that exists to compare a signed to unsigned: it already knows that A is signed, so out of the 5 possibilities that "10101010" could be(string, bit_vector, std_logic_vector, signed, unsigned), it knows to pick signed. If you wrote this:

    if a = true then

    there is no = for signed and boolean, so it throws an error.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    @Tricky, now that is what I call a great post! Wow, you have certainly opened my mind up here. BTW Apologies for delayed response, caught a cold!

    I see now why something would simulate and not synthesize. I also wondered how exactly an actual FPGA could support signals which could be in an X, U, - W H or L state. In fact it doesn't - this is only for synthesis.

    Understanding that what I assumed were 'numbers' are NOT! They are strings! This to me was the key that unlocked the fundamental understanding of what is going on. As a result, something seemingly innocuous as this:

    
      signal count : STD_LOGIC_VECTOR (7 downto 0);
      count <= count + 1;
      if count = b"00000000" then
        blah;
    

    is not as simple as it first appears. I have to stop thinking in terms of code! The '+' is a function! the 1 is an integer! And the comparison is only true if ALL states match 0 and could indeed be Z,X,H,L,- etc. Maybe better to avoid STD_LOGIC_VECTOR and stick to using SIGNED and UNSIGNED where possible. And if adding, maybe design an actual adder if using STD_LOGIC_VECTOR?

    I am glad I started this thread. What an eye opener!

    Thanks again,

    Andy
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    you dont really need to worry about states other than 1 and 0 - they will show up easily in simulation and will be a sign something isnt right. if an X occured, then the synthesisor would fail anyway as it doesnt allow two signals to drive the same bus.

    As for basics, an adder is very basic, and can probably build a better one than you can, so +1 is just fine. it is also much more abstract and ports across chips and vendors. A hand build adder for one chip may not be optimal for another - let the synthesisor do the hard work for you - you just get on with easy to read code.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    "I am now trying to do for a Camputers Lynx."

    Hi Andy can you PM me - we're both working on the same project it seems :)

    I'm trying to do it in wishbone z80. Pete
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Is the In_clk on the board twice as fast as the one you created in simulation?

    on a design note: what is in_e? you are using it as if it were a clock - assuming it is an enable (because it looks like one) this is a bad idea. For a start, assuming in_e is a clock, you are not transfering the reg values into the in_clk domain safely, so you're liable to create meta-stable states on your registers that read the reg values. You should clock all the regs at in_clk (all processes) and then use the in_e as a clock enable:

    
    if falling_edge(in_clk) then
      if in_e = '1' then
        --do some registering
    

    Secondly, is there a good reason for using the falling edge? it is usual to use the rising edge.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Is the In_clk on the board twice as fast as the one you created in simulation?

    --- Quote End ---

    Nope. It is produced from a set of master clocks I have set up in my FPGA. This particular clocking signal, when taken to an output pin of the FPGA runs at the correct frequency (and mark to space), i.e. 750KHz.

    From the data sheet of this particular IC I am attempting to implement:

    --- Quote Start ---

    E = Enable pin (I called IN_E). Enables the data-bus input/output buffers and clocks data to & from this device. This signal is usually derived from the system clock.

    --- Quote End ---

    I understand what you are saying there about this signal. Wise words. I will rewrite it to common up the clocking event.

    BUT! If I hard code the register (the bold code above) to instead to be a the fixed (programmed) value that I expect it to be, i.e:

    
    IF usg_Cntr_HorizAll_7_0 = x"2F" THEN
      blah
    

    or

    
    IF usg_Cntr_HorizAll_7_0 = b"00101111" THEN
      blah
    

    Still the same! simulates at 64uS, FPGA output pin 32uS.

    So, 750KHz = 1.333333uS. 2F = 47: 0..47=48 counts. 48 x 1.3333333uS = 64uS.

    Why do I have a falling edge clocking event you ask:

    From the data sheet of IC I am attempting to implement:

    --- Quote Start ---

    The CLK is an input used to sync all CRT (i.e. this IC) functions except for the processor interface (hence the strange instantiation of IN_E). The active transition is high-to-low

    --- Quote End ---

    So yes, negative edge triggered.

    Thank you AGAIN,

    Andy