Author Topic: VHDL add and divide  (Read 3857 times)

0 Members and 1 Guest are viewing this topic.

Offline gaminnTopic starter

  • Frequent Contributor
  • **
  • Posts: 338
  • Country: 00
VHDL add and divide
« on: July 23, 2019, 07:57:36 pm »
Hi,
i have some sequential logic and three std_logic_vector(7 downto 0) signals, signal1, signal2 and output. I want to do this:

if rising_edge(clk16) then
-- set output to sum of signal1 and signal2 divided by 2, take into account possible overflow - sum of two 8bit vectors can be 9bit vector
-- equivalent c code is output = (signal1 + signal2) / 2
end if;

Any idea?
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4278
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: VHDL add and divide
« Reply #1 on: July 23, 2019, 08:34:14 pm »
variable v_sum : std_logic_vector (8 downto 0);

v_sum := signal1 + signal2;
output <= v_sum (8 downto 1);
 
The following users thanked this post: gaminn

Offline gaminnTopic starter

  • Frequent Contributor
  • **
  • Posts: 338
  • Country: 00
Re: VHDL add and divide
« Reply #2 on: July 23, 2019, 09:34:42 pm »
Thanks.
 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: VHDL add and divide
« Reply #3 on: July 23, 2019, 10:15:17 pm »
variable v_sum : std_logic_vector (8 downto 0);

v_sum := signal1 + signal2;
output <= v_sum (8 downto 1);

Let's clarify.

Code: [Select]
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity add_divide is
    port (
        clk : in std_logic;
        signal1 : in std_logic_vector(7 downto 0);
        signal2 : in std_logic_vector(7 downto 0);
        sigout  : out std_logic_vector(7 downto 0));
end entity add_divide;

architecture ad is
    signal sum : unsigned(8 downto 0);
begin
    adddiv : process (clk) is
    begin
        if rising_edge(clk) then
            -- assuming unsigned inputs, zero-extend them to allow for the possible overflow.
            -- vectors on the RHS must be the same size as the assignment target on the RHS
            -- (does VHDL 2008 handle mis-matched sizes? I don't know and I don't care)
            sum <= resize(unsigned(signal1), sum'length) + resize(unsigned(signal2), sum'length);
        end if;

        -- output is the sum divided by two. Taking the upper 8 bits is effectively a left shift.
        sigout <= std_logic_vector(sum(8 downto 1));
end architecture ad;
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15274
  • Country: fr
Re: VHDL add and divide
« Reply #4 on: July 23, 2019, 10:45:44 pm »
That's how I would do it as well.

Just note that you don't formally have to resize both terms of the sum, one of them would be enough (but it's probably more readable to resize both):

Quote
When both operands to a binary arithmetic functions + or - are either SIGNED or UNSIGNED, the function
returns a value with the same number of elements (bits) as the larger of the two operands.

This quote is from IEEE Std 1076.3-1997, so that was possible way before VHDL 2008.

But you are right in resizing. You have to resize at least one of them, otherwise the sum would be with the same number of bits as the operands (which is not what the OP asked), and the result would not be 1 bit wider anyway, so you could not assign it to a vector which is 1 bit wider.

Edit: (That's something missing in AndyC_772's code. He also uses arithmetic on std_logic_vector, which I really do not recommend. This was the old Synopsys way. I don't know if the result of a sum would automatically be 1 bit wider with Synopsys' libraries or not...)

Quick notes:
- I think there's a missing "end process" in your code. ^-^
- Small bonus: you could avoid the hard-coded slice at the end like so:
Code: [Select]
sigout <= std_logic_vector(resize(shift_right(sum, 1), sigout'length));
« Last Edit: July 23, 2019, 11:21:06 pm by SiliconWizard »
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4278
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: VHDL add and divide
« Reply #5 on: July 24, 2019, 07:18:08 am »
It's probably also worth clarifying whether or not either of the initial values can be negative, because that does change the outcome.

Bear in mind, there's no overhead in converting signals between formats. If you want to explicitly convert the original signals into unsigned integers, then add them, then convert back to a vector, then that's completely free in terms of speed and resource utilisation.

Offline David Hess

  • Super Contributor
  • ***
  • Posts: 17113
  • Country: us
  • DavidH
Re: VHDL add and divide
« Reply #6 on: July 24, 2019, 02:23:38 pm »
How is the addition actually realized in hardware?  Is a larger word width used or does it just rely on the carry bit?
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8755
  • Country: fi
Re: VHDL add and divide
« Reply #7 on: July 24, 2019, 03:05:34 pm »
How is the addition actually realized in hardware?  Is a larger word width used or does it just rely on the carry bit?

Very often with typical bog-standard ripple carry adders. The hardware is synthesized for any arbitrary number of bits. The highest one, of course, is just the carry bit alone from the lower stage.
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9932
  • Country: us
Re: VHDL add and divide
« Reply #8 on: July 24, 2019, 03:20:20 pm »
If you read some of the literature on the CLBs (Configurable Logic Block) they will discuss how each block has a carry chain routed through it whether it is used as an adder or not.
See page 43:

https://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf
 
The following users thanked this post: SiliconWizard

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 15274
  • Country: fr
Re: VHDL add and divide
« Reply #9 on: July 24, 2019, 04:10:55 pm »
It's probably also worth clarifying whether or not either of the initial values can be negative, because that does change the outcome.

Yes. We assumed those were all unsigned numbers...

That's also why I personally avoid using std_logic_vector's as types for my entities' ports when the underlying use is meant to be signed or unsigned integers. In that case, I define the corresponding ports as signed or unsigned instead, that conveys the intent much more clearly. I convert to std_logic_vector in higher levels when and only if needed (for instance for external signals).

Bear in mind, there's no overhead in converting signals between formats. If you want to explicitly convert the original signals into unsigned integers, then add them, then convert back to a vector, then that's completely free in terms of speed and resource utilisation.

Absolutely. It's just that the IEEE's numeric_std is standard and a pretty sane implementation of integer operations.
Conversions in themselves cost nothing. Likewise, the use of the "shift_right" function (from numeric_std) I suggested will in the end get the exact same synthesis result as using a slice. I just found it conveys the meaning more clearly, and would have the added benefit of correctly handling sign bits if the numbers where signed ones.



 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: VHDL add and divide
« Reply #10 on: July 24, 2019, 04:30:29 pm »
It's probably also worth clarifying whether or not either of the initial values can be negative, because that does change the outcome.

Yes. We assumed those were all unsigned numbers...

That's also why I personally avoid using std_logic_vector's as types for my entities' ports when the underlying use is meant to be signed or unsigned integers. In that case, I define the corresponding ports as signed or unsigned instead, that conveys the intent much more clearly. I convert to std_logic_vector in higher levels when and only if needed (for instance for external signals).

I agree with this, and use it all the time.

Quote
Bear in mind, there's no overhead in converting signals between formats. If you want to explicitly convert the original signals into unsigned integers, then add them, then convert back to a vector, then that's completely free in terms of speed and resource utilisation.

Absolutely. It's just that the IEEE's numeric_std is standard and a pretty sane implementation of integer operations.
Conversions in themselves cost nothing. Likewise, the use of the "shift_right" function (from numeric_std) I suggested will in the end get the exact same synthesis result as using a slice. I just found it conveys the meaning more clearly, and would have the added benefit of correctly handling sign bits if the numbers where signed ones.

The language (unlike Verilog) gives us these very useful tools that indicate the designer's intent. Everyone should use them!

 

Offline asmi

  • Super Contributor
  • ***
  • Posts: 2794
  • Country: ca
Re: VHDL add and divide
« Reply #11 on: July 24, 2019, 06:29:27 pm »
The language (unlike Verilog) gives us these very useful tools that indicate the designer's intent. Everyone should use them!
Verilog does it too, it just doesn't force you into using it.

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8084
  • Country: ca
Re: VHDL add and divide
« Reply #12 on: July 24, 2019, 11:36:23 pm »
The language (unlike Verilog) gives us these very useful tools that indicate the designer's intent. Everyone should use them!
Verilog does it too, it just doesn't force you into using it.
Thank you...  I don't know how many times VHDL programmers here on this forum make such comments about Verilog never reading up properly on the language or how to implement such strict definition controls which are available.
 

Offline asmi

  • Super Contributor
  • ***
  • Posts: 2794
  • Country: ca
Re: VHDL add and divide
« Reply #13 on: July 25, 2019, 12:44:48 am »
Thank you...  I don't know how many times VHDL programmers here on this forum make such comments about Verilog never reading up properly on the language or how to implement such strict definition controls which are available.
I would add that SystemVerilog takes this to the next level and allows enforcing types compatibility if that's something designer wants or needs at the level of individual wire/reg.
But my personal favorite SV feature is interface, which makes interconnecting modules radically easier. Here is what typical module declaration looks like:
Code: [Select]
module prepare #(
    parameter ADDRESS_WIDTH = 64,
    parameter DATA_WIDTH = 64,
    parameter CMD_WIDTH = 32
)(
    input clk,
    input cpu_reset,
    input enable,

    decoder_out_intf.in in_bus,
    prepare_out_intf.out out_bus,
    control_intf.prep ctrl_bus
);
Last three ports are "modports" which enforces both naming and directions of the individual wires, but more importantly, if I need to add a wire into the "bus", I only need to add its declaration to the interface definition and relevant modports, and it will "automagically" appear on all "sides" of that bus, sparing me from having to copy-paste connecting wires all over the place.
Connecting such modules is trivial too:
Code: [Select]
prepare #(
    .ADDRESS_WIDTH(ADDRESS_WIDTH),
    .DATA_WIDTH(DATA_WIDTH),
    .CMD_WIDTH(CMD_WIDTH)
) prepare_inst (
    .clk,
    .cpu_reset,
    .enable(enable_prep),
    .in_bus(decoder_out_bus),
    .out_bus(prepare_out_bus),
    .ctrl_bus(control_bus)
);
Clean and beautiful, isn't it? :-+
 
The following users thanked this post: BrianHG


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf