Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.

numbers, numbers...

Altera_Forum
Honored Contributor II
2,231 Views

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
0 Kudos
17 Replies
Altera_Forum
Honored Contributor II
1,458 Views

Hi, 

First you made a pseudo gated clock with a different "clock"which is bad. I suggest you to resynchronize with your system clock (IN_CLK).  

Even if it makes sense in VHDL, It is smarter using a whole unique system clock (IN_CLK) in this case. 

You can correct this with :  

ext_write : process(IN_RESETn, IN_CLK) begin if IN_RESETn = '0' then REG_R00_HORIZ_TOTAL_7_0 <= b"0010_1111"; elsif falling_edge (IN_CLK) then if 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  

 

Secondly,  

LIBRARY ieee; USE ieee.STD_LOGIC_1164.all; -- 'Z' 'X' '1' '0' 'W' 'U' 'L' 'H' '-' USE ieee.numeric_std.all; -- UNSIGNED, SIGNED, + - * / mod
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

Thank you for your response! 

 

Now, this bit you've suggested... 

elsif falling_edge (IN_CLK) then if falling_edge(IN_E) and IN_CSn='0' and IN_RW='0' then --Grab data from data bus and program into indexed register.  

... I see TWO clock events in the SAME process. I did not think you could do that?! Based on the fact I have tried to do this in the past and just got errors. 

 

Andy
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

You cannot use two clock events in the same process - how do you expect this to work? the two clocks would have to be exactly co-incident for it to even work conceptually, but there is no way it will work on real hardware. 

 

But mtushi is correct in saying using gated clocks is a bad idea. So do not use in_e as a clock - use the in_clk as the clock and in_e as enable: 

 

elsif falling_edge (IN_CLK) then if IN_E = '1' and IN_CSn='0' and IN_RW='0' then --Grab data from data bus and program into indexed register.  

 

And yes, also stop using std_logic_arith. It is not a standard VHDL package, numeric_std is. 

 

If the hard coded value gives a different result to the register version, I can only assume the CPU is writing the wrong number.
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

So, not 'good practice' to use a signal logic operators with a clocking event. Gotcha. Do them separately. Roger will-co. 

 

Yes, I have read that std_logic_arith is a non-standard package. Having admitted my guilt over this, as a newbie VHDLer, changing something which at the higher level simulates spot on, is something I was reluctant to do but I will now see if I can change over to using the standard library. I know I will get errors because I am using a MAKE_BINARY function: 

 

library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.math_real.all; package CONFIG is -- Convert UNSIGNED type to STD_LOGIC_VECTOR type function MAKE_BINARY(A : UNSIGNED) return STD_LOGIC_VECTOR; ..etc.. end package CONFIG; package body CONFIG is type tbl_type is array (STD_ULOGIC) of STD_ULOGIC; constant tbl_BINARY : tbl_type := ('X', 'X', '0', '1', 'X', 'X', '0', '1', 'X'); function MAKE_BINARY(A : UNSIGNED) return STD_LOGIC_VECTOR is variable one_bit : STD_ULOGIC; variable result : STD_LOGIC_VECTOR (A'range); begin for i in A'range loop result(i) := tbl_BINARY(A(i)); end loop; return result; end; end CONFIG;  

Yes, I copied that lot (not my own, hell I'm learning VHDL ;) ). No doubt more non-standard horribleness. 

 

 

--- Quote Start ---  

If the hard coded value gives a different result to the register version, I can only assume the CPU is writing the wrong number.  

--- Quote End ---  

 

Maybe. But the signals are (as far as I can tell) that come from my core processor when first programming this VHDL model of my 'chip' are spot on as well. The simulator couldn't 'see' these actual register contents, so I might now simply add a vector such that I can monitor the register contents. 

 

Thanks again! 

 

Andy
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

your "make_binary" function is redundant for your code as it is now. As unsigned and std_logic_vector are closely related types (they are both arrays of std_logic) you can convert from one to the other using a simple type case: 

 

my_slv <= std_logic_vector(my_us); 

my_us <= unsigned(my_slv); 

 

it also does some X01 conversion, there already exists a function for this, called to_X01. 

 

my_slv <= to_X01(my_slv); 

 

But why do you want to have only 'X' and 0 or 1? the 'U' value lets you know in simulation that something hasnt been initialised properly. and how are you going to cope with 'Z' when you need to build a tri-state driver? 

 

It seems you're re-writing code that already exists, and you probably dont need to use them anyway.
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

 

--- Quote Start ---  

It seems you're re-writing code that already exists, and you probably don't need to use them anyway.  

--- Quote End ---  

 

Yes, some of it (as admitted above). And therein 'learning'... the hard way I guess. ;) 

 

What is X01? Google time (again).. 

 

Now we are getting to the nitty-gritty of VHDL number systems. Good. I likey. This is what I would very much like to get a firm grasp of. 

 

Thank you again (for bearing with my most basic of questions). A lot of info on this on the internet, but far too 'varied' and in some cases contradictory, hence this thread really. 

 

Andy
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

It might be easier if you try and explain what you are trying to do. 

 

VHDL has no special number system. I think you're getting confused over the typing system. 

An integer in VHDL is just a number. If used in synthesisable code, the synthesisor should convert it into a 32 bit 2's compliment notation. 

The numeric_std library defines the unsigned and signed types. unsigned is pure 2^n logic, signed is 2s complement. But the reason we use unsigned is as followed: 

 

1. It gives access to the bits inside the VHDL code. 

2. We can set the length ourselves. 

 

(these two also hold true for std_logic_vector also) 

 

3. We can do arithmatic with it. 

4. It will roll over - integer type will not (this is useful for things like address generation for FIFOs). 

 

So, I think you're trying to run before you can walk. re-writing the basics that already exist in VHDL show you're trying too much too soon and overcomplicating your learning.
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

All true. 

 

Been learning for about 6 months now, due in main to there being a MASSIVE hole in my CV where 'FPGA' & 'VHDL' should be written. Got hold of FreeRange VHDL tutorial and went from there. After getting bored with making numbers appear on a HEX display on my version of the Papilio Pro board, I thought 'sod it, I wonder if I can can make an entire computer run in my FPGA'. Like they did for the ZX Spectrum, I am now trying to do for a Camputers Lynx. 

 

Using the OpenCores Z80 (T80 core) I found it amazingly simple for my FPGA to run the original ROM code as a VHDL LUT. In went all the glue logic (re-written many times as I learn the correct way to do things), block RAM acting as old-school DRAM etc. That works. Then went in sound, and it 'Beeps' now when powered up, just like the original Lynx. Now to make something appear on an old TV. To do that, the old Lynx computer uses a CRTC6845 chip. Again, on OpenCores, there it was so in it went (little point in reinventing the wheel). Unfortunately that core for the 6845 was not complete, so I have rewritten almost all of it and now it works (OK, simulates)... but as a result of trying to unravel it I see non-standard libraries and as you've pointed out, unnecessary functions. So I will re-write that to make it more compatible and 'correct'. 

 

Yes I am learning, but the way I learn is through practice and by chucking myself in at the deep end and I never give up! Admittedly, a bit ar$e about face way of learning but there you go that's just the way I am. I am enjoying learning VHDL so much (apart from the many, many frustrations in getting my brain to work) and in doing so, dispelling the old theory that you cannot teach an old dog new tricks. I'm getting there (he says). 

 

Thank you again for taking the time to respond to my thread! 

 

Andy
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

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. 

 

use ieee.numeric_std.all;  

A standard library one would want to use. 

It defines (among other things I guess): 

UNSIGNED SIGNED + - * / mod  

So that simple signed and unsigned math can be used on vectors: add, subtract, multiply, divide and modulus. 

 

Also comparisons (operators) between vectors of whatever type, SIGNED or UNSIGNED: 

= /= <= >= > <  

 

So thinking ahead then, if I wish to use a counter which I know I will want to add 1 to it periodically and then compare it to another number... hence I would want to declare it as an UNSIGNED (or SIGNED): 

signal counter : UNSIGNED (7 downto 0);  

 

And hence in a process somewhere, this is therefore OK to then do if I want to increase that counter by 1: 

counter <= counter + 1;  

 

Now I want to compare that number to another number say from a data-bus at a certain point in time. the data bus is however declared thus: 

DataBus_7_0 : in STD_LOGIC_VECTOR (7 downto 0);  

 

So, in order to match the two types, one must therefore 'cast' into the numeric_std type as this is where the compare '=' operator is defined. 

Am I right in assuming this is how this is done correctly: 

if counter = UNSIGNED(DataBus_7_0) then do_something_very_cool;  

 

But what about comparing to a fixed number? Is this OK: 

if counter = b"0010_0000" then do_something_even_cooler;  

Question here: that number: b"0010_0000" isn't really a 'number' per-se is it? The above comparison will actually be a logical comparison of bits yes? in other words it is both SIGNED and UNSIGNED if you get my drift? Or is this a necessity instead (or 'better practice')?: 

if counter = UNSIGNED(b"0010_0000") then do_make_Andy_cool_and_not_a_pedantic_nerd;  

 

Cheers, 

 

Andy
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

if counter = b"0010_0000" then do_something_even_cooler; 

I suggest  

if counter = 32 then 

 

Unsigned or signed compare operations are performed with integer values as well.
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

 

--- 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.
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

@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
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

"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
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

TO_BE_DONE

0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
1,458 Views

 

--- 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
0 Kudos
Reply