How does a 32:8 mux work? - vhdl

I'm programming a 32:8 mux in vhdl.
The task is based on a exam question that oviously can be interpreted several ways. The origianal task was to: Program a 32:8 mux, using "with select when", and "if then else". I did'nt get how the 32:8 mux would work, so I did'nt know where to start, but thanks to you guys I figured I would program it as a 4:1 mux passing 4 groups of 8 bits.
This is what I got:
library ieee;
use ieee.std_logic_1164.all;
entity mux_using_with is
port (
input :in std_logic_vector (31 downto 0);
sel :in std_logic_vector (1 downto 0);
mux_out :out std_logic_vector (7 downto 0));
end entity;
architecture behavior of mux_using_with is
begin
with (sel) select
mux_out <= input(7 downto 0) when '00',
input(15 downto 8) when '01',
input(23 downto 16) when '10',
input(31 downto 24) when others;
end architecture;
And for the if version:
library ieee;
use ieee.std_logic_1164.all;
entity mux_using_if is
port (
input :in std_logic_vector (31 downto 0);
sel :in std_logic_vector (1 downto 0);
mux_out :out std_logic_vector (7 downto 0));
end entity;
architecture behavior of mux_using_if is
begin
MUX:
process (sel, input) begin
if (sel = '00') then
mux_out <= input(7 downto 0);
elsif (sel = '00') then
mux_out <= input(15 downto 8);
elsif (sel = '00') then
mux_out <= input(23 downto 16);
else
mux_out <= input(31 downto 24);;
end if;
end process;
end architecture;
Have I made any obvious mistakes?

A 32:8 selects 8 bits from 32 bits. There are two obvious ways to do this (and other less obvious ones):
Select any contiguous group of 8 bits starting from any point in the 32-bit input, with possible wrap-around. This is actually a 'barrel shifter'. There are 32 'start' positions, so you need a 5-bit selector; or
Select one of the 4 groups [7:0], [15:8], [23:16], or [31:24]. In this case, you need a 2-bit selector to select one of these groups.
I'm going to assume you want (2), since you've got a 2-bit selector. So, each of your 8 output bits is actually a 4:1 mux. Bit 0 of the output selects from either bit 0, 8, 16, or 24 of the input, for example, depending on the state of your 2-bit selector.
There are 4 straightforward ways to do this in VHDL: a sequential case statement, a selected signal assignment, direct logic, or array element selection. There are examples of all 4 styles on the Maia site. These only have a 1-bit output, so your task is to turn it into an 8 bit output. Have a look and let us know if you have a problem.

Related

8 bit serial to parallel shifter in vhdl

I programmed an 8-bit shifter in vhdl:
entity 8b is
port(s, clk : in std_logic; p : out std_logic_vector (7 downto 0));
end entity;
architecture arch of 8b is
Signal iq : std_logic_vector (7 downto 0);
begin
process(clk)
begin
if rising_edge(clk) then
iq(7) <= s;
iq(6 downto 0) <= iq(7 downto 1);
end if;
end process;
p <= iq;
end architecture;
The idea is that I'm taking input and giving it to my first D-FF.
Then over the next 7 cycles, the other Flip Flops get the other serial inputs which will be given to the parallel output p.
However, I'm not sure if this logic is flawed because this is the solution we got for this exercise:
architecture behavior of 8b is
signal p_intern : std_logic_vector(7 downto 0);
begin
P <= p_intern;
process(CLK)
begin
if rising_edge(CLK) then
p_intern <= p_intern(6 downto 0) & S;
end if;
end process;
end architecture;
But I don't get the p_intern <= p_inter(6 downto 0) & S; part.
Can someone please explain the logic behind this and if my version is also valid?
The only difference between the two implementations seem to be the lines
iq(7) <= s;
iq(6 downto 0) <= iq(7 downto 1);
vs.
p_intern <= p_intern(6 downto 0) & S;
and that iq is named p_intern. Let's assume they are both named iq for the sake of comparison.
Let's see what they are doing:
The first implementation (yours) assigns to the positions of iq:
7 6 5 ... 1 0
s iq(7) iq(6) ... iq(2) iq(1)
The second implementation (the solution) assigns
7 6 5 ... 1 0
iq(6) iq(5) iq(4) ... iq(0) s
Where iq(6 downto 0) & s means "concatenate s to the right of iq(6 downto 0)".
So they are not equivalent. Your implementation shifts in the values from the left, and the solution shifts in the values from the right. Which one is correct depends on the specification (presumably the solution is correct).

FSM for 4-bit UP-counter on VHDL

Hay, I've coded my 4-bit up counter already but I need some help with this certain part.
The up counter works fine but I need to make some changes to my input so it follows my lab requirement.
Design a 4-bit UP-counter which counts from 0 through n and follows the sequence
[0, n^0+a, n^1+a, n^2+a, n^3+a, ....].
I'm suppose to use two input vectors of n and a and they both are 2-bits each. My clock suppose to be connected into SW0, also, I'm suppose to connect n to SW1-SW2 and a to SW3-SW4.
I've already connected everything I just need help and understanding on how can I implement a and n in the following code.
As the instructions says I can not use Multipliers or Adders.
Any help would be appreciated.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
entity upCounter is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
--n : in STD_LOGIC_VECTOR (1 downto 0);
--a : in STD_LOGIC_VECTOR (1 downto 0);
output : out STD_LOGIC_VECTOR (3 downto 0)
);
end upCounter;
architecture Behavioral of upCounter is
signal count: STD_LOGIC_VECTOR (3 downto 0);
begin
process (clk, reset)
begin
if reset = '1' then
count <= "0000";
elsif clk'event and clk = '1' then
count <= count + 1;
end if;
end process;
output <= count;
end Behavioral;

Specialized calculator using VHDL

I have to project a specialized calculator on a Basys3 board using VHDL. The calculator should be able to group numbers using brackets, perform additions and substractions, AND and OR operations. For example, an expression could be: 4 + 5 AND 6 +(7 OR 1) - (4 AND 10)
The input numbers are 4 bit numbers (in my code I used 5 bit numbers, the most significant bit being the sign bit) and the output can be max. 16 bits long (i used 17 bits in my code, the most significant being the sign bit).
I wrote the code for the ALU (the adder/substractor, AND/OR) and I managed to make the calculator work for 2 numbers as inputs(using 2 in ports). This is the "main" code for the calculator, that i have written:
library IEEE;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_UNSIGNED.all;
entity calculator is
port(X: in STD_LOGIC_VECTOR(4 downto 0); -- X(4) sign
Y: in STD_LOGIC_VECTOR(4 downto 0);
OPERATIE: in STD_LOGIC_VECTOR(4 downto 0);
CLK, CLR: in STD_LOGIC;
a_to_g: out STD_LOGIC_VECTOR(6 downto 0);
an: out STD_LOGIC_VECTOR(3 downto 0);
negativ: out std_logic);
end calculator;
architecture calculator of calculator is
component ALU is
port(A,B: in STD_LOGIC_VECTOR(16 downto 0);
COMANDA: in STD_LOGIC_VECTOR(4 downto 0);
RESULT: out STD_LOGIC_VECTOR(16 downto 0));
end component;
component BCD_7seg is
port(X: in STD_LOGIC_VECTOR(15 downto 0);
CLK, CLR: in STD_LOGIC;
a_to_g: out STD_LOGIC_VECTOR(6 downto 0);
an: out STD_LOGIC_VECTOR(3 downto 0));
end component;
signal OPERAND_1: STD_LOGIC_VECTOR(16 downto 0) := (others => '0');
signal OPERAND_2: STD_LOGIC_VECTOR(16 downto 0) := (others => '0');
signal TEMP_RESULT: STD_LOGIC_VECTOR(16 downto 0) := (others => '0');
begin
operand_1(3 downto 0) <= x(3 downto 0);
operand_1(16) <= x(4);
operand_2(3 downto 0) <= y(3 downto 0);
operand_2(16) <= y(4);
calculate: ALU port map(operand_1, operand_2, operatie, temp_result);
afis: BCD_7seg port map(temp_result(15 downto 0), clk, clr, a_to_g, an);
negativ <= temp_result(16);
end calculator;
However, the calculator should work for N numbers as inputs (using only one in port) and I don't know how to do it. I thought about memorising the whole expression(operartors and operands) in a FIFO or LIFO memory (but I'm not sure if that could work) and then making the calculations but I don't know how to calculate everything in the correct order given by the priorities and where(and how) to memorise the temporary results.
I thought that maybe you could give me some ideas, I'm new to VHDL, I'm a student and I have just started learning it and got stuck at this part in the project.
Thanks!

Use of conv_integer in VHDL

I am in the process of trying to write some code that will simply just shift a 32 bit vector left or right, with a 5 bit input that will be used for the shift amount (shamt). The issue I am having is trying to convert an std_logic_vector to an integer. My code is this:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x : in std_logic_vector(31 downto 0);
shamt : in std_logic_vector( 4 downto 0);
y : out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
signal shift : integer;
signal temp : std_logic_vector(31 downto 0);
begin
shift <= conv_integer(unsigned(shamt));
temp <= x(shift downto 0);
y <= temp;
end beh;
The code is not complete I know, but to test some ideas I am trying to pass "00010" (2) into shamt, but shift comes out to be -2147483648. But I cannot figure out why it is doing this, nor can I find any resources online that shows anything different than what I am doing. I greatly appreciate any help.
-2147483648 (-2**31) is the default initial value for integers, being the leftmost, most negative value in its range. It suggests that the signal assignment to shift has not executed. Most likely because it is a continuous assignment and there hasn't been an event on shamt to cause it to update.
std_logic_arith is not an IEEE standard library. You should use to_integer() from ieee.numeric_std instead. It is also beneficial to keep numeric ports as unsigned or signed so that your intent is clear and to minimize type conversions. Also, you cannot directly assign the variable length slice of x to temp since their lengths do not match. You should use resize() (from numeric_std) to extend the length back to 32-bits or rethink your approach.
I fixed the obvious typo in the entity name, started the simulation (ModelSim) and forced the signal shamt to "00010". Then just after trying to run for 1 ps, ModelSim complains about:
Fatal: (vsim-3420) Array lengths do not match. Left is 32 (31 downto 0). Right is 0 (-2147483648 downto 0 (null array)).
Time: 0 ps Iteration: 0 Process: /shiftlogical/line__16 File: shiftlogical.vhdl
Fatal error in Architecture beh at shiftlogical.vhdl line 16
That is because all your concurrent statements are executed in parallel. The new signal values are scheduled for the next delta cycle within the simulation. Thus, the line
temp <= x(shift downto 0);
is executed with the old value of shift which is the initial value of this signal. The initial value of an integer is -2**31 as also Kevin pointed out.
Of course you can initialize the signal shift, but the only value which will not result in an error will be 31 because in this asignment the signal on the left and the expression on the right must match in array (std_logic_vector) size. The signal shamt must be forced to "11111" as well, so that shift keeps 31.
You cannot easily fix this, because for a left shift you must add zeros at the right (LSB) and for a right shift zeros or the sign at the left (MSB).
#Martin Zabel what I had really tested there was to see if shift would hold an integer value which it did until I tried to pass it in for temp <= x(shift downto 0); What I realized was that the signal needed to really be a variable to work as intended and as follows my code consists of:
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.STD_LOGIC_ARITH.all;
entity shiftlogical is
port(x: in std_logic_vector(31 downto 0);
shamt: in std_logic_vector(4 downto 0);
dir: in std_logic;
y: out std_logic_vector(31 downto 0));
end shiftlogical;
architecture beh of shiftlogical is
begin
process(dir)
variable shift : integer;
begin
shift := conv_integer(unsigned(shamt));
if(dir = '0') then --Left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
elsif(dir = '1') then --Right shift
y(31-shift downto 0) <= x(31 downto shift);
y(31 downto 31-shift) <= (others => '0');
else --Always left shift
y(31 downto shift) <= x(31-shift downto 0);
y(shift downto 0) <= (others => '0');
end if;
end process;
end beh;

How to convert 8 bits to 16 bits in VHDL?

I have an input signal from ADC convertor that is 8 bits (std_logic_vector(7 downto 0)). I have to convert them to a 16 bits signal (std_logic_vector(15 downto 0)) for 16 bits signal processing to the 16 bits system.
If the 8 bit value is interpreted as signed (2's complement), then the general and standard VHDL conversion method is to use the IEEE numeric_std library:
library ieee;
use ieee.numeric_std.all;
architecture sim of tb is
signal slv_8 : std_logic_vector( 8 - 1 downto 0);
signal slv_16 : std_logic_vector(16 - 1 downto 0);
begin
slv_16 <= std_logic_vector(resize(signed(slv_8), slv_16'length));
end architecture;
So first the std_logic_vector is converted to a signed value, then the resize is applied, which will sign extend the signed value, and the result is finally converted back to std_logic_vector.
The conversion is rather lengthy, but has the advantage that it is general and works even if the target length is changed later on.
The attribute 'length simply returns the length of the slv_16 std_logic_vector, thus 16.
For unsigned representation instead of signed, it can be done using unsigned instead of signed, thus with this code:
slv_16 <= std_logic_vector(resize(unsigned(slv_8), slv_16'length));
architecture RTL of test is
signal s8: std_logic_vector(7 downto 0);
signal s16: std_logic_vector(15 downto 0);
begin
s16 <= X"00" & s8;
end;
This handles the conversion without having to edit the widths of the zeroes if either std_logic_vector changes:
architecture RTL of test is
signal s8: std_logic_vector(7 downto 0);
signal s16: std_logic_vector(15 downto 0) := (others => '0');
begin
s16(s8'range) <= s8;
end;
For completeness, yet another way which is occasionally useful:
-- Clear all the slv_16 bits first and then copy in the bits you need.
process (slv_8)
begin
slv_16 <= (others => '0');
slv_16(7 downto 0) <= slv_8;
end process;
I've not had to do this for vectors that I can recall, but I have had need of this under more complex circumstances: copying just a few relevant signals into a bigger, more complex, record was one time.
With the newly released VHDL-2019 standard you can do
larger_vec <= extend(shorter_vec);
where extend is a function defined as follows
function extend(vec : std_logic_vector) return target_vec of std_logic_vector is
variable result : std_logic_vector(target_vec'length - 1 downto 0) := (others => '0');
begin
assert vec'length <= target_vec'length report "Cannot extend to shorter vector";
result(vec'length - 1 downto 0) := vec;
return result;
end function;
Tool support is still a bit limited but at least one simulator supports this (Riviera-PRO).

Resources