??? 06/20/08 18:32 Read: times |
#156074 - bzzzzzzzzzzzt! Responding to: ???'s previous message |
Richard Erlacher said:
Andy Peters said:
But you still haven't answered my question. What is the decimal equivalent to the binary vector "10010110"? The answer makes it obvious why VHDL handles numbers as it does. I don't know why that's an issue but if it's what it appears to be, namely a bit vector, then the first element is 1 which makes it a HEX 69, which is decimal 96+9 or 105. You fell into my carefully-plotted trap! Actually, the value is 0x96. If you want unsigned decimal, then your decimal number is 150. But if you want a signed decimal, then that same bit vector represents -106. It should be obvious why this is important! What puzzles me is why so many textbooks on VHDL simply fail to discuss the business of the various data types and their purpose, and when they're of benefit, not to mention the business of translating from one to the other. I think that Ashenden, esp. the 2nd edition, does a good job of this. See chapter 8. The book that came with the Cypress tools is so old, and the version of the language that those tools supported is obsolete, so you're best off pulping the book. Running the counter in type natural is fine until you have to generate STD_LOGIC_VECTOR output from it because it's an address counter in a DMA Channel. Then, too, you'd want to decode various strobes from the low-order bits ... How would that work without type conversion? You can do a handful of things. a) Code your DMA channel logic to use naturals for its address counter. b) don't use natural, use numeric_std's unsigned type. Say you have a 16-bit address space. Declare your counter as an unsigned(15 downto 0). Arithmetic operations work as you expect. But dig this: if, for example, you wish to use the 4 LSbs as a mux select, just use 'em: architecture foo of bar is signal count : unsigned(15 downto 0); signal mux : std_logic; signal this, that, theother : std_logic; -- mux inputs begin -- architecture CountAndMux : process(clk) is begin if rising_edge(clk) then if (rst = '1') then count <= (others => '0'); mux <= '0'; else count <= (count + 1) mod 65536; FooMux : case count(1 downto 0) is when "00" => mux <= '0'; when "01" => mux <= this; when "10" => mux <= that; when "11" => mux <= theother; end case Foomux; end if; -- reset end if; -- clock end process CountAndMux; end architecture foo;So, you're asking, "Why does that mux select work?" Simple ... the unsigned (and its brother, signed) in numeric_std are bit vectors. In fact, they are "closely related" to std_logic_vector, which is why the conversion between the two is a type cast and not a function call. Since count is a bit vector, you can pick out any of the bits and use them individually however you wish, just like it was a type bit_vector or a type std_logic_vector. c) Use natural, and use range decoders. Synthesis tools are pretty smart. For example, the following synthesizes to the simple comparator you expect: architecture bada of bing is subtype nat16_t : natural range 0 to 65535; constant A_BASE : nat16_t := X"F000"; constant A_TOP : nat16_t := X"F0FF"; signal myaddr : nat16_t; signal select : std_logic; begin select <= '1' when (myaddr >= A_BASE) and (myaddr < A_TOP) else '0'; end architecture bada; Can you recommend of a text that actually goes into meaningful and exhaustive detail about when you'd want to use one type over another? Ashenden. But I think it's really up to the designer what makes the most sense. Basically, if the number is used only in an entity, then use natural or integer. If the value needs to go out of the entity, then do a conversion at the boundary. If you need to use bit parts of the value, then maybe unsigned or signed is what you want. Finally, the SynthWorks people have a very good introduction (pdf) to the various numeric types. Really, this isn't at all complicated. -a |