- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
if counter = b"0010_0000" then
do_something_even_cooler;
if counter = 32 then
Unsigned or signed compare operations are performed with integer values as well.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
"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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
TO_BE_DONE
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page