VHDL add and divide - Page 1
Forum section: electronics / general

author: gaminn
author_rank: Frequent Contributor
timestamp: July 23, 2019, 07:57:36 pm
content: 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) / 2end if;Any idea?

author: AndyC_772
author_rank: Super Contributor
timestamp: July 23, 2019, 08:34:14 pm
content: variable v_sum : std_logic_vector (8 downto 0);v_sum := signal1 + signal2;output <= v_sum (8 downto 1);

author: gaminn
author_rank: Frequent Contributor
timestamp: July 23, 2019, 09:34:42 pm
content: Thanks.

author: Bassman59
author_rank: Super Contributor
timestamp: July 23, 2019, 10:15:17 pm
content: Quote from: AndyC_772 on July 23, 2019, 08:34:14 pmLet's clarify.Code:library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity add_divide isport (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 issignal sum : unsigned(8 downto 0);beginadddiv : process (clk) isbeginif 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;

author: SiliconWizard
author_rank: Super Contributor
timestamp: July 23, 2019, 10:45:44 pm
content: 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):QuoteThis 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:sigout <= std_logic_vector(resize(shift_right(sum, 1), sigout'length));

author: AndyC_772
author_rank: Super Contributor
timestamp: July 24, 2019, 07:18:08 am
content: 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.

author: David Hess
author_rank: Super Contributor
timestamp: July 24, 2019, 02:23:38 pm
content: How is the addition actually realized in hardware? Is a larger word width used or does it just rely on the carry bit?

author: Siwastaja
author_rank: Super Contributor
timestamp: July 24, 2019, 03:05:34 pm
content: Quote from: David Hess on July 24, 2019, 02:23:38 pmVery 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.

author: rstofer
author_rank: Super Contributor
timestamp: July 24, 2019, 03:20:20 pm
content: 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

author: SiliconWizard
author_rank: Super Contributor
timestamp: July 24, 2019, 04:10:55 pm
content: Quote from: AndyC_772 on July 24, 2019, 07:18:08 amYes. 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).Quote from: AndyC_772 on July 24, 2019, 07:18:08 amAbsolutely. 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.

author: Bassman59
author_rank: Super Contributor
timestamp: July 24, 2019, 04:30:29 pm
content: Quote from: SiliconWizard on July 24, 2019, 04:10:55 pmI agree with this, and use it all the time.QuoteThe language (unlike Verilog) gives us these very useful tools that indicate the designer's intent. Everyone should use them!

author: asmi
author_rank: Super Contributor
timestamp: July 24, 2019, 06:29:27 pm
content: Quote from: Bassman59 on July 24, 2019, 04:30:29 pmVerilog does it too, it just doesn't force you into using it.

author: BrianHG
author_rank: Super Contributor
timestamp: July 24, 2019, 11:36:23 pm
content: Quote from: asmi on July 24, 2019, 06:29:27 pmThank 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.

author: asmi
author_rank: Super Contributor
timestamp: July 25, 2019, 12:44:48 am
content: Quote from: BrianHG on July 24, 2019, 11:36:23 pmI 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: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: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?