Using array of std_logic_vector as a port type, with both ranges using a generic - vhdl

Is it possible to create an entity with a port that is an array of std_logic_vectors, with both the size of the array and the std_logic_vector coming from generics? Ie. is it possible to create eg. a bus multiplexer with both the bus width and bus count configurable?
entity bus_multiplexer is
generic (bus_width : positive := 8;
sel_width : positive := 2);
port ( i : in array(integer range 2**sel_width - 1 downto 0) of std_logic_vector(bus_width - 1 downto 0);
sel : in std_logic_vector(sel_width - 1 downto 0);
o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer;
architecture dataflow of bus_multiplexer is
begin
o <= i(to_integer(unsigned(sel)));
end dataflow;
The above doesn't seem to work because the array type needs to be defined separately.
Defining the type before the port also does not work, as then it expects the entity definition to end after it. Defining it after the port definition doesn't work since it'd be used before that. Defining it in a package doesn't work because the type definition doesn't seem to like having an unconstrained range in the "base type".
Is it possible to somehow do this in VHDL-93? (What about VHDL-2008?)
Defining the type as array(natural range <>, natural range <>) of std_logic in the package works - as in the port definition doesn't give an error - but actually using it if it's defined that way seems to be quite unwieldy.
Is there some sane way to use it like this? Is there some simple way to map N separate std_logic_vectors to a port defined like that, and likewise for the actual output logic?
I tried the original and o <= i(to_integer(unsigned(sel)), bus_width - 1 downto 0), but neither worked. I know I could do it one bit at a time, but I'd prefer something simpler. And while the bit-by-bit -approach might be okay for the internal implementation, I certainly wouldn't want to have to do that for the port mapping every time I use the component...
Is there some sane(-ish) way to do this?
(Addendum: I know there are some similar questions, but most of them don't deal with the case of both ranges coming from generics, and were solved using a type definition in a package. The one that did talk about two generic dimensions apparently didn't need the input to come from distinct std_logic_vectors and ended up using the "2d-array of std_logic" method, which doesn't work for me (at least without further clarification about how to use it without losing one's sanity))

This works with VHDL2008:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package bus_multiplexer_pkg is
type bus_array is array(natural range <>) of std_logic_vector;
end package;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.bus_multiplexer_pkg.all;
entity bus_multiplexer is
generic (bus_width : positive := 8;
sel_width : positive := 2);
port ( i : in bus_array(2**sel_width - 1 downto 0)(bus_width - 1 downto 0);
sel : in std_logic_vector(sel_width - 1 downto 0);
o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer;
architecture dataflow of bus_multiplexer is
begin
o <= i(to_integer(unsigned(sel)));
end dataflow;
And it can be used like this:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.all;
use work.bus_multiplexer_pkg.all;
entity bus_multiplexer_4 is
generic (bus_width : positive := 8);
port ( bus0, bus1, bus2, bus3 : in std_logic_vector(bus_width - 1 downto 0);
sel : in std_logic_vector(1 downto 0);
o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer_4;
architecture structural of bus_multiplexer_4 is
signal i : bus_array(3 downto 0)(bus_width - 1 downto 0);
begin
i <= (0 => bus0, 1 => bus1, 2 => bus2, 3 => bus3);
u: entity bus_multiplexer generic map (bus_width => bus_width, sel_width => 2) port map (i => i, sel => sel, o => o);
end;
It doesn't work with VHDL93, however, because you can't leave the std_logic_vector unconstrained in the type definition, as stated in the question.
Unfortunately, I don't know if there's any way to do anything similar without 2d arrays with VHDL93.
Edit: Paebbels's answer shows how to do this in VHDL93 by using 2d arrays, with custom procedures to make it manageable. Since his example is quite big, here's also a minimal example of the same concept:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
package bus_multiplexer_pkg is
type bus_array is array(natural range <>, natural range <>) of std_logic;
procedure slm_row_from_slv(signal slm : out bus_array; constant row : natural; signal slv : in std_logic_vector);
procedure slv_from_slm_row(signal slv : out std_logic_vector; signal slm : in bus_array; constant row : natural);
end package;
package body bus_multiplexer_pkg is
procedure slm_row_from_slv(signal slm : out bus_array; constant row : natural; signal slv : in std_logic_vector) is
begin
for i in slv'range loop
slm(row, i) <= slv(i);
end loop;
end procedure;
procedure slv_from_slm_row(signal slv : out std_logic_vector; signal slm : in bus_array; constant row : natural) is
begin
for i in slv'range loop
slv(i) <= slm(row, i);
end loop;
end procedure;
end package body;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.bus_multiplexer_pkg.all;
entity bus_multiplexer is
generic (bus_width : positive := 8;
sel_width : positive := 2);
port ( i : in bus_array(2**sel_width - 1 downto 0, bus_width - 1 downto 0);
sel : in std_logic_vector(sel_width - 1 downto 0);
o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer;
architecture dataflow of bus_multiplexer is
begin
slv_from_slm_row(o, i, to_integer(unsigned(sel)));
end dataflow;
And it can be used like this:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.all;
use work.bus_multiplexer_pkg.all;
entity bus_multiplexer_4 is
generic (bus_width : positive := 8);
port ( bus0, bus1, bus2, bus3 : in std_logic_vector(bus_width - 1 downto 0);
sel : in std_logic_vector(1 downto 0);
o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer_4;
architecture structural of bus_multiplexer_4 is
signal i : bus_array(3 downto 0, bus_width - 1 downto 0);
begin
slm_row_from_slv(i, 0, bus0);
slm_row_from_slv(i, 1, bus1);
slm_row_from_slv(i, 2, bus2);
slm_row_from_slv(i, 3, bus3);
u: entity bus_multiplexer generic map (bus_width => bus_width, sel_width => 2) port map (i => i, sel => sel, o => o);
end;

Yes, it's possible.
Your attempt with a two dimensional array is good, because nested 1 dimensional array need a fixed size in the inner dimensions. So the way to handle such a 2D array is to write some functions and procedures, which convert the 2D array into nested 1D vectors.
I answered a similar question here:
- Fill one row in 2D array outside the process (VHDL) and
- Creating a generic array whose elements have increasing width in VHDL
Here is my vectors package.
And here is an example of an multiplexer for a FIFO interface, which is variable in data width as well as in input count. It uses a round robin arbiter to select the inputs.
Entity 'PoC.bus.Stream.Mux':
-- EMACS settings: -*- tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
--
-- ============================================================================
-- Authors: Patrick Lehmann
--
-- License:
-- ============================================================================
-- Copyright 2007-2015 Technische Universitaet Dresden - Germany
-- Chair for VLSI-Design, Diagnostics and Architecture
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- ============================================================================
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
library PoC;
use PoC.config.all;
use PoC.utils.all;
use PoC.vectors.all;
entity Stream_Mux is
generic (
PORTS : POSITIVE := 2;
DATA_BITS : POSITIVE := 8;
META_BITS : NATURAL := 8;
META_REV_BITS : NATURAL := 2
);
port (
Clock : IN STD_LOGIC;
Reset : IN STD_LOGIC;
-- IN Ports
In_Valid : IN STD_LOGIC_VECTOR(PORTS - 1 downto 0);
In_Data : IN T_SLM(PORTS - 1 downto 0, DATA_BITS - 1 downto 0);
In_Meta : IN T_SLM(PORTS - 1 downto 0, META_BITS - 1 downto 0);
In_Meta_rev : OUT T_SLM(PORTS - 1 downto 0, META_REV_BITS - 1 downto 0);
In_SOF : IN STD_LOGIC_VECTOR(PORTS - 1 downto 0);
In_EOF : IN STD_LOGIC_VECTOR(PORTS - 1 downto 0);
In_Ack : OUT STD_LOGIC_VECTOR(PORTS - 1 downto 0);
-- OUT Port
Out_Valid : OUT STD_LOGIC;
Out_Data : OUT STD_LOGIC_VECTOR(DATA_BITS - 1 downto 0);
Out_Meta : OUT STD_LOGIC_VECTOR(META_BITS - 1 downto 0);
Out_Meta_rev : IN STD_LOGIC_VECTOR(META_REV_BITS - 1 downto 0);
Out_SOF : OUT STD_LOGIC;
Out_EOF : OUT STD_LOGIC;
Out_Ack : IN STD_LOGIC
);
end;
architecture rtl OF Stream_Mux is
attribute KEEP : BOOLEAN;
attribute FSM_ENCODING : STRING;
subtype T_CHANNEL_INDEX is NATURAL range 0 to PORTS - 1;
type T_STATE is (ST_IDLE, ST_DATAFLOW);
signal State : T_STATE := ST_IDLE;
signal NextState : T_STATE;
signal FSM_Dataflow_en : STD_LOGIC;
signal RequestVector : STD_LOGIC_VECTOR(PORTS - 1 downto 0);
signal RequestWithSelf : STD_LOGIC;
signal RequestWithoutSelf : STD_LOGIC;
signal RequestLeft : UNSIGNED(PORTS - 1 downto 0);
signal SelectLeft : UNSIGNED(PORTS - 1 downto 0);
signal SelectRight : UNSIGNED(PORTS - 1 downto 0);
signal ChannelPointer_en : STD_LOGIC;
signal ChannelPointer : STD_LOGIC_VECTOR(PORTS - 1 downto 0);
signal ChannelPointer_d : STD_LOGIC_VECTOR(PORTS - 1 downto 0) := to_slv(2 ** (PORTS - 1), PORTS);
signal ChannelPointer_nxt : STD_LOGIC_VECTOR(PORTS - 1 downto 0);
signal ChannelPointer_bin : UNSIGNED(log2ceilnz(PORTS) - 1 downto 0);
signal idx : T_CHANNEL_INDEX;
signal Out_EOF_i : STD_LOGIC;
begin
RequestVector <= In_Valid AND In_SOF;
RequestWithSelf <= slv_or(RequestVector);
RequestWithoutSelf <= slv_or(RequestVector AND NOT ChannelPointer_d);
process(Clock)
begin
if rising_edge(Clock) then
if (Reset = '1') then
State <= ST_IDLE;
else
State <= NextState;
end if;
end if;
end process;
process(State, RequestWithSelf, RequestWithoutSelf, Out_Ack, Out_EOF_i, ChannelPointer_d, ChannelPointer_nxt)
begin
NextState <= State;
FSM_Dataflow_en <= '0';
ChannelPointer_en <= '0';
ChannelPointer <= ChannelPointer_d;
case State is
when ST_IDLE =>
if (RequestWithSelf = '1') then
ChannelPointer_en <= '1';
NextState <= ST_DATAFLOW;
end if;
when ST_DATAFLOW =>
FSM_Dataflow_en <= '1';
if ((Out_Ack AND Out_EOF_i) = '1') then
if (RequestWithoutSelf = '0') then
NextState <= ST_IDLE;
else
ChannelPointer_en <= '1';
end if;
end if;
end case;
end process;
process(Clock)
begin
if rising_edge(Clock) then
if (Reset = '1') then
ChannelPointer_d <= to_slv(2 ** (PORTS - 1), PORTS);
elsif (ChannelPointer_en = '1') then
ChannelPointer_d <= ChannelPointer_nxt;
end if;
end if;
end process;
RequestLeft <= (NOT ((unsigned(ChannelPointer_d) - 1) OR unsigned(ChannelPointer_d))) AND unsigned(RequestVector);
SelectLeft <= (unsigned(NOT RequestLeft) + 1) AND RequestLeft;
SelectRight <= (unsigned(NOT RequestVector) + 1) AND unsigned(RequestVector);
ChannelPointer_nxt <= std_logic_vector(ite((RequestLeft = (RequestLeft'range => '0')), SelectRight, SelectLeft));
ChannelPointer_bin <= onehot2bin(ChannelPointer);
idx <= to_integer(ChannelPointer_bin);
Out_Data <= get_row(In_Data, idx);
Out_Meta <= get_row(In_Meta, idx);
Out_SOF <= In_SOF(to_integer(ChannelPointer_bin));
Out_EOF_i <= In_EOF(to_integer(ChannelPointer_bin));
Out_Valid <= In_Valid(to_integer(ChannelPointer_bin)) and FSM_Dataflow_en;
Out_EOF <= Out_EOF_i;
In_Ack <= (In_Ack 'range => (Out_Ack and FSM_Dataflow_en)) AND ChannelPointer;
genMetaReverse_0 : if (META_REV_BITS = 0) generate
In_Meta_rev <= (others => (others => '0'));
end generate;
genMetaReverse_1 : if (META_REV_BITS > 0) generate
signal Temp_Meta_rev : T_SLM(PORTS - 1 downto 0, META_REV_BITS - 1 downto 0) := (others => (others => 'Z'));
begin
genAssign : for i in 0 to PORTS - 1 generate
signal row : STD_LOGIC_VECTOR(META_REV_BITS - 1 downto 0);
begin
row <= Out_Meta_rev AND (row'range => ChannelPointer(I));
assign_row(Temp_Meta_rev, row, i);
end generate;
In_Meta_rev <= Temp_Meta_rev;
end generate;
end architecture;

Related

Can't normally see result in wave (Modesim)

I have code designed for Vivid software. How I can translate this code into ModelSIM? In vivado, I should get the following values, but in modelsim I get completely different ones.
This is noise generator. Successful in adding pseudorandom noise sequence to our sine wave, but now we are trying to add Gaussian noise. The code and the simulation results for ADDITION OF PSEUDORANDOM NOISE SEQUENCE TO SINE WAVE IS GIVEN BELOW:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL; --try to use this library as much as possible.
entity sine_wave is
generic ( width : integer := 4 );
port (clk :in std_logic;
random_num : out std_logic_vector (width-1 downto 0);
data_out : out STD_LOGIC_VECTOR(7 downto 0)
);
end sine_wave;
architecture Behavioral of sine_wave is
signal data_out1,rand_temp1,noisy_signal : integer;
signal noisy_signal1 : STD_LOGIC_VECTOR(7 downto 0);
signal i : integer range 0 to 29:=0;
--type memory_type is array (0 to 29) of integer;
type memory_type is array (0 to 29) of std_logic_vector(7 downto 0);
--ROM for storing the sine values generated by MATLAB.
signal sine : memory_type := ("01001101","01011101","01101100","01111010","10000111","10010000","10010111","10011010","10011010");
--hi
begin
process(clk)
variable rand_temp : std_logic_vector(width-1 downto 0):=(width-1 => '1',others => '0');
variable temp : std_logic := '0';
begin
--to check the rising edge of the clock signal
if(rising_edge(clk)) then
temp := rand_temp(width-1) xor rand_temp(width-2);
rand_temp(width-1 downto 1) := rand_temp(width-2 downto 0);
rand_temp(0) := temp;
--data_out <= sine(i);
i <= i+ 1;
if(i = 29) then
i <= 0;
end if;
end if;
data_out <= sine(i);
data_out1<=to_integer(unsigned(sine(i)));
random_num <= rand_temp;
rand_temp1<=to_integer(unsigned(rand_temp));
noisy_signal<=data_out1+rand_temp1;
noisy_signal1<= std_logic_vector(to_signed(noisy_signal,8));
end process;
end Behavioral;
Vivado
ModelSIM

How to write a record to memory and get it back in VHDL?

In VHDL pseudo-code what I would like to achieve is:
type tTest is record
A : std_logic_vector(3 downto 0);
B : std_logic_vector(7 downto 0);
C : std_logic_vector(0 downto 0);
end record tTest;
. . .
signal sTestIn : tTest;
signal sMemWrData : std_logic_vector(fRecordLen(tTest)-1 downto 0);
signal sMemRdData : std_logic_vector(fRecordLen(tTest)-1 downto 0);
signal sTestOut : tTest;
. . .
sMemWrData <= fRecordToVector(sTestIn);
-- At some point sMemRdData gets the data in sMemWrData...
sTestOut <= fVectorToRecord(sMemRdData);
fRecordLen is an imaginary function that returns the aggregate length of record directly from the type and fRecordToVector and fVectorToRecord are hopefully self explanatory. The target is synthesizable code that doesn't produce any extra logic. I post my current solution as an answer to further clarify the operation. However this is extremely awkward method and I don't consider it as a feasible solution due to the amount of boiler plate code.
I am aware of record introspection proposal but not holding my breath and even the proposed method seems very cumbersome.
I've given up hope for a fully general solution, so some concessions are more than acceptable. For example, allow only std_logic_vectors in the record and use several function/procedure calls. However, it would be great to avoid any boiler-plate code that must be hand or external script-adjusted per-record basis.
Also, if any Verilog/SystemVerilog wrappers exist that can input/output the record directly and achieve the same, pointers are extremely welcome.
One way to translate data from a vector (a linear array) to a record would be through the use of an aggregate.
library ieee;
use ieee.std_logic_1164.all;
package TestPck is
subtype A is std_logic_vector (12 downto 9);
subtype B is std_logic_vector (8 downto 1);
subtype C is std_logic_vector (0 downto 0);
constant ABC_len: natural := A'length + B'length + C'length;
type tTest is record
A: std_logic_vector (A'RANGE);
B: std_logic_vector (B'RANGE);
C: std_logic_vector (C'RANGE);
end record tTest;
type tTests is array (natural range <>) of tTest;
end package TestPck;
library ieee;
use ieee.std_logic_1164.all;
use work.TestPck.all;
entity tb is
end entity tb;
architecture sim of tb is
signal sTestIn: tTest;
signal sMemWrData: std_logic_vector(ABC_len - 1 downto 0);
signal sMemRdData: std_logic_vector(ABC_len - 1 downto 0);
signal sTestOut: tTest;
constant tests: tTests (0 to 1) :=
(0 => (x"E", x"A7", "1"), 1 => (x"7", x"AC", "0"));
begin
sMemWrData <= sTestIn.A & sTestIn.B & sTestIn.C;
sMemRdData <= sMemWrData after 5 ns;
sTestOut <=
tTest'(sMemRdData(A'range), sMemRdData(B'range), SMemRdData(C'range));
process is
begin
wait for 10 ns;
sTestIn <= tests(0);
wait for 10 ns;
sTestIn <= tests(1);
wait for 10 ns;
wait;
end process;
end architecture sim;
The qualified expression defines the aggregate as a value of tTest record with positional association which is assigned to the record type sTestOut.
And this gives:
So you can use concatenation for assembling a vector value (or an aggregate in -2008) and use an aggregate as a qualified expression to transfer sMemRdData to sTestOut.
If you have no plans to declare an object of an A, B or C subtype you can declare them as integer subtypes:
library ieee;
use ieee.std_logic_1164.all;
package TestPck is
subtype A is natural range 12 downto 9;
subtype B is natural range 8 downto 1;
subtype C is natural range 0 downto 0;
constant ABC_len: natural := A'left + 1;
type tTest is record
A: std_logic_vector (A);
B: std_logic_vector (B);
C: std_logic_vector (C);
end record tTest;
type tTests is array (natural range <>) of tTest;
end package TestPck;
library ieee;
use ieee.std_logic_1164.all;
use work.TestPck.all;
entity tb is
end entity tb;
architecture sim of tb is
signal sTestIn: tTest;
signal sMemWrData: std_logic_vector(ABC_len - 1 downto 0);
signal sMemRdData: std_logic_vector(ABC_len - 1 downto 0);
signal sTestOut: tTest;
constant tests: tTests (0 to 1) :=
(0 => (x"E", x"A7", "1"), 1 => (x"7", x"AC", "0"));
begin
sMemWrData <= sTestIn.A & sTestIn.B & sTestIn.C;
sMemRdData <= sMemWrData after 5 ns;
sTestOut <=
tTest'(sMemRdData(A), sMemRdData(B), SMemRdData(C));
process is
begin
wait for 10 ns;
sTestIn <= tests(0);
wait for 10 ns;
sTestIn <= tests(1);
wait for 10 ns;
wait;
end process;
end architecture sim;
This may be a little easier to read. It'll produce the same waveform above.
This a one way to achieve what is requested. The shortcomings/improvement ideas are in the comments.
library ieee;
use ieee.std_logic_1164.all;
package TestPck is
type tTest is record
A : std_logic_vector(3 downto 0);
B : std_logic_vector(7 downto 0);
C : std_logic_vector(0 downto 0);
end record tTest;
procedure pSliceToFrom (
signal vec_to : out std_logic_vector;
signal vec_from : in std_logic_vector;
position : inout integer
);
end package TestPck;
package body TestPck is
procedure pSliceToFrom (
signal vec_to : out std_logic_vector;
signal vec_from : in std_logic_vector;
position : inout integer
) is
begin
vec_to <= vec_from(position-1 downto position-vec_to'length);
position := position-vec_to'length;
end pSliceToFrom;
end package body TestPck;
library ieee;
use ieee.std_logic_1164.all;
use work.TestPck.all;
entity tb is
end entity tb;
architecture sim of tb is
signal sTestIn : tTest;
-- How to create this constant in the package,
-- i.e. without needing the signal?
constant cTestLength : integer := sTestIn.A'length + sTestIn.B'length + sTestIn.C'length;
signal sMemWrData : std_logic_vector(cTestLength-1 downto 0);
signal sMemRdData : std_logic_vector(cTestLength-1 downto 0);
signal sTestOut : tTest;
begin
-- How to make this without needing to know what
-- is inside tTest?
sMemWrData <= sTestIn.A & sTestIn.B & sTestIn.C;
-- Memory, Fifo, communication link, doesn't matter...
sMemRdData <= sMemWrData after 5 ns;
-- How to get the data back without needing this
-- process (and the procedure)?
slice_data_to_item : process (all) is
variable vPosition : integer := 0;
begin
vPosition := cTestLength;
pSliceToFrom(sTestOut.A, sMemRdData, vPosition);
pSliceToFrom(sTestOut.B, sMemRdData, vPosition);
pSliceToFrom(sTestOut.C, sMemRdData, vPosition);
end process slice_data_to_item;
process is
begin
wait for 10 ns;
sTestIn <= (x"E", x"A7", "1");
wait for 10 ns;
sTestIn <= (x"7", x"AC", "0");
wait;
end process;
end architecture sim;

Implementing Overflow Checking in 4-bit Adder/Subtractor (VHDL)

I am rather new (3 weeks) to VHDL, and I am having a problem in my latest assignment, which involves implementing overflow checking in a simple 4-bit adder:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity add_sub_4bit is
Port ( a : in STD_LOGIC_VECTOR(3 downto 0);
b : inout STD_LOGIC_VECTOR(3 downto 0);
sel: in STD_LOGIC );
--sum : inout STD_LOGIC_VECTOR(3 downto 0)
end add_sub_4bit;
architecture Behavioral of add_sub_4bit is
signal localflow : STD_LOGIC;
signal localsum : STD_LOGIC_VECTOR (3 downto 0);
begin
localsum <= a + b when sel = '1'
else
a - b;
process(a,b,localsum) begin
if a(3) = '0' AND b(3) = '0' AND localsum(3) = '1' then
localflow <= '1';
elsif a(3) = '1' AND b(3) = '1' AND localsum(3) = '0' then
localflow <='1';
else
localflow <='0';
end if;
end process;
end Behavioral;
Now, the test cases are as such:
A=5, B=-3, giving 0 to sel adds them, 1 subtracts.
A=6, B=2, working much the same.
Now, given that the numbers are signed, of course, they are two's complement numbers, so is the result. However, I can only detect overflow in a case of adding 6 (0110) and 2 (0010), giving out -8 (1000), which is obviously an overflow case in 4-bit. But, when doing 5 -(-3), the result is much the same, 1000, but since I have given numbers of two different signs, I cannot detect overflow using my method.
My teacher has suggested that we change the sign of B depending on the value of sel - I tried something like making b <= b+"1000" based on that but that didn't help, and I don't know of other ways, being very new to the language. What can I do to get a proper program? Thank you.
Firstly:
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Don't do that. Especially if you want the numbers to be signed. Normal to use is:
use IEEE.numeric_std.all;
After that, you should cast the std_logic_vector to the wanted data type, e.g. 'signed', for the correct arithmetic.
Secondly, don't use inout. VHDL is not so good with bidirectional assignments. Either use in or out.
So combining the above, you could do (n.b. not the best code):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity add_sub_4bit is
Port (
a : in STD_LOGIC_VECTOR(3 downto 0);
b : in STD_LOGIC_VECTOR(3 downto 0);
sel: in STD_LOGIC;
sum : out STD_LOGIC_VECTOR(3 downto 0);
overflow : out std_logic
);
end add_sub_4bit;
architecture Behavioral of add_sub_4bit is
signal localflow : STD_LOGIC;
signal locala, localb, localsum : signed(4 downto 0); -- one bit more then input
signal sumout : std_logic_vector(4 downto 0);
begin
locala <= resize(signed(a), 5);
localb <= resize(signed(b), 5);
localsum <= locala + localb when sel = '1' else locala - localb;
-- overflow occurs when bit 3 is not equal to the sign bit(4)
localflow <= '1' when localsum(3) /= localsum(4) else '0';
-- convert outputs
sumout <= std_logic_vector(localsum);
--outputs
sum <= sumout(4)&sumout(2 downto 0);
overflow <= localflow;
end Behavioral;
You can test this using a testbench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity add_sub_4bit_tb is
end add_sub_4bit_tb;
architecture Behavioral of add_sub_4bit_tb is
signal sel : std_logic_vector(0 downto 0);
signal a, b, sum : std_logic_vector(3 downto 0);
begin
uut: entity work.add_sub_4bit
port map (a, b, sel(0), sum);
test: process
begin
for sel_o in 0 to 1 loop
sel <= std_logic_vector(to_signed(sel_o, 1));
for a_o in -8 to 7 loop
a <= std_logic_vector(to_signed(a_o, 4));
for b_o in -8 to 7 loop
b <= std_logic_vector(to_signed(b_o, 4));
wait for 1 ns;
end loop;
end loop;
end loop;
wait;
end process;
end Behavioral;

VHDL 2008 and CASE statement

I've a question about a case statement and VHDL 2008. I've an entity defined in this way :
entity multiplier_v2 is
generic( WIDTH_WORD : integer := 32;
WIDTH_RSA : integer := 2048;
LENGTH_ADDRESS : integer := 6 );
port (
reset : in std_logic;
clk : in std_logic;
start : in std_logic;
input_1 : in std_logic_vector(WIDTH_WORD - 1 downto 0);
input_2 : in std_logic_vector(WIDTH_WORD - 1 downto 0);
module : in std_logic_vector(WIDTH_WORD - 1 downto 0);
output : out std_logic_vector(WIDTH_WORD - 1 downto 0);
ack_data : out std_logic;
data_valid : out std_logic;
new_module : in std_logic;
Inside the module I've a signal declared in this way :
signal counter_ack : std_logic_vector(LENGTH_ADDRESS - 1 downto 0);
I use this signal in a case statement :
case counter_ack is
when (others => '1') =>
ack_data <= '0';
when others =>
counter_ack <= counter_ack + 1;
end case;
Now, I'm pretty sure that VHDL-2008 option is enabled in my synthesis tool but I have the following error regarding that part of my code:
2049990 ERROR - E:/My_Designs/Custom Module/Montgomery_Multiplier/Diamond/src/multiplier_v2.vhd(456,6-461,15) (VHDL-1544) array type case expression must be of a locally static subtype
I've read that this error should be fixed in VHDL-2008. Any ideas ?
I compiled the code displayed below in Quartus II with VHDL 2008 compiler option. I got no error. Does your case statement is in a process?
LIBRARY ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_signed.all;
ENTITY casestate IS
generic( WIDTH_WORD : integer := 32;
WIDTH_RSA : integer := 2048;
LENGTH_ADDRESS : integer := 6 );
port (
reset : in std_logic;
clk : in std_logic;
ack_data : out std_logic
);
END casestate;
ARCHITECTURE fpga OF casestate IS
signal counter_ack : std_logic_vector(LENGTH_ADDRESS - 1 downto 0);
BEGIN
process(clk,reset)
begin
if(reset = '0')then
ack_data <= '0';
elsif(rising_edge(clk))then
case counter_ack is
when (others => '1') =>
ack_data <= '0';
when others =>
counter_ack <= counter_ack + 1;
ack_data <= '1';
end case;
end if;
end process;
end fpga;
You need to specify the range, (others => '1') is an unconstrained vector
So you could do something like
when (counter_ack'range => '1') =>
which is a vector of defined length that should work in more software that doesn't make inferences.
this also works for if statements
if VEC = (VEC'range => '0') then
CODE
end if;

Generating a generic delay package in VHDL

I'm looking for the correct syntax to build a generic line delay package using generics and for loops in a process. I understand that for loops when used with generate are for concurrent statements, but surely there must be a way to build it.
For example:
entity Delay_Line is
Generic (
CLK_DELAYS : integer := 10);
Port (
CLK : in STD_LOGIC;
i_Din : in STD_LOGIC;
o_Q : out STD_LOGIC;
o_Qnot : out STD_LOGIC);
end Delay_Line;
architecture Delay_Line_arch of Delay_Line is
signal din_dly : std_logic_vector(CLK_DELAYS-1 downto 0);
begin
din_dly(0) <= i_Din;
process(CLK)
begin
if rising_edge(CLK) then
for index in 0 to CLK_DELAYS-1 generate
begin
din_dly(index+1) <= din_dly(index);
end;
end if;
end process;
o_Q <= din_dly(CLK_DELAYS);
o_Qnot <= NOT (din_dly(CLK_DELAYS));
end Delay_Line_arch;
Typically I would just add a bunch of:
din_delay(9) <= din_delay(8);
din_delay(8) <= din_delay(7);
...
in the code, but honestly I'd like something a little more reusable as a package.
It isn't really necessary to use such elaborate methods to implement shift registers. You can implement them directly in one line using array concatenation and slicing.
constant DELAY_STAGES : positive := 10; -- Or use a generic parameter
signal delay_line : std_logic_vector(1 to DELAY_STAGES);
...
process(clk) is
begin
if rising_edge(clk) then
delay_line <= i_Din & delay_line(1 to DELAY_STAGES-1); -- Shift right
end if;
end process;
-- Retrieve the end of the delay without a hard-coded index
o_Q <= delay_line(delay_line'high);
The brevity of this approach pretty much eliminates any convenience of having a component that you need to instantiate with port and generic maps. Plus you have the flexibility of being able to tap off whatever intermediate signals you may need.
Well I don’t have 50 rep yet but to get Pablo R’s method to work with large busses and delays bus_size := 16 and delay := 256. I had to change:
temp_bus2 <= i_bus2 & temp_bus2(delay*bus_size - 1 downto (delay-1)*bus_size);
to
temp_bus2 <= i_bus2 & temp_bus2(delay*bus_size - 1 downto (bus_size);
A bit late, but this is my generic_delay component:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY generic_delay is
generic (
bus_size : natural;
delay : natural
);
port (
i_Clock : IN STD_LOGIC;
i_reset : IN STD_LOGIC;
i_bus1 : in std_logic_vector(bus_size - 1 downto 0);
i_bus2 : in std_logic_vector(bus_size - 1 downto 0);
o_bus1 : out std_logic_vector(bus_size - 1 downto 0);
o_bus2 : out std_logic_vector(bus_size - 1 downto 0)
);
end generic_delay;
architecture a of generic_delay is
----------------------------
-- SIGNALS DECLARATION
----------------------------
signal temp_bus1 : std_logic_vector(delay*bus_size - 1 downto 0);
signal temp_bus2 : std_logic_vector(delay*bus_size - 1 downto 0);
BEGIN
-----------------------------------------
-- SYNCHRONOUS PROCESS
-----------------------------------------
process(i_Clock, i_reset)
begin
if i_reset = '1' then
temp_bus1 <= (others => '0');
temp_bus2 <= (others => '0');
elsif falling_edge(i_Clock) then
if delay > 1 then
temp_bus1 <= i_bus1 & temp_bus1(delay*bus_size - 1 downto (delay-1)*bus_size);
temp_bus2 <= i_bus2 & temp_bus2(delay*bus_size - 1 downto (delay-1)*bus_size);
else
temp_bus1 <= i_bus1;
temp_bus2 <= i_bus2;
end if;
elsif (RISING_EDGE(i_Clock)) then
o_bus1 <= temp_bus1(bus_size - 1 downto 0);
o_bus2 <= temp_bus2(bus_size - 1 downto 0);
end if; -- reset + rising_edge(clk)
end process logic;
-------------------------------------------------------
end a;

Resources