# How can I add a signed vector with an unsigned one in VHDL?

I would like to know how can I add an unsigned vector with a signed one. The reason is that I am creating a MIPS processor and I would like to add the program counter which is unsigned with the immediate field of I-Type instruction which is signed. Below you can see the datapath and the addition of those 2 vectors.

I've already tried the following resulting in error:

-- Signals used
PC_BRANCH_DEC_OUT   : out std_logic_vector(31 downto 0);
PC_PLUS4_DEC_IN     : in std_logic_vector (31 downto 0);
signal signed_imm_s : std_logic_vector    (31 downto 0);

-- Addition of the signals above
PC_BRANCH_DEC_OUT <= std_logic_vector(unsigned(PC_PLUS4_DEC_IN) + signed(signed_imm_s));


The aforementioned addition works only if both are unsigned or signed.

Is there a workaround to make this addition possible and how?

• Do you need to be able to decrease the program counter using this code, or should the immediate value always be positive? – scary_jeff Aug 31 '16 at 15:38
• I would like to increase/decrease the program counter using the immediate field. It's essentially the branch instruction. – Spyros Chiotakis Aug 31 '16 at 15:40
• With two's complement numbers, there is no difference between signed and unsigned additions, you can use unsigned everywhere. (This is different, for example, with multiplications, which are different for signed and unsigned numbers) – TEMLIB Aug 31 '16 at 20:54

Why are you keeping the program counter in a std_logic_vector? This data type is meant for a bundle of independent std_logic values, while the bits in your program counter are not independent as there is carry during addition.

I'd implement the entire program counter as an unsigned, which allows using addition operators directly.

• Thank you for the insight! I refactored the code to integer where needed and I have escaped from a lot of "to_integer" casts plus I got my problem solved. – Spyros Chiotakis Sep 1 '16 at 17:49

The easiest way might be to to convert both signals to an integers, add them, and then convert back to signed. There are to_integer functions for both signed and unsigned. You can also try simply typecasting the unsigned signal into a signed signal, however that might turn 15 ("unsigned 1111") into -1 ("signed 1111"), and might mess up your addition.

All you need to do is extend the unsiged program counter to make it a signed value, perform the addition with the signed immediate value, then chop off the sign bit:

signal pc_signed : signed (32 downto 0);
signal new_pc_signed : signed (32 downto 0);


...

pc_signed <= signed ('0' & PC_PLUS4_DEC_IN);
new_pc_signed <= pc_signed + signed(signed_imm_s);
PC_BRANCH_DEC_OUT <= std_logic_vector(unsigned(new_pc_signed(31 downto 0)));


There is obvious potential here for something bad to happen if an instruction tries to move the PC below zero, but I suppose it would be up to the programmer to make sure that this did not happen. You could add checks for this in hardware if you wanted; just check for the most significant bit in new_pc_signed being set.

As someone else pointed out, you would be better off with ports and signals that represent numbers having a numerical type, so your program counter would be unsigned throughout. This would avoid having so many type conversions everywhere. It seems to be a common complaint that awkward looking type conversions are 'required', when the real solution to this is often to just use more appropriate types in the first place.

• I refactored the code to integers where needed as you said and got my problem solved. I made my life harder by using the std_logic_vector type where it wasn't necessary. – Spyros Chiotakis Sep 1 '16 at 17:51