Accessing part of std_logic_vector using variables as indexes - vhdl

I am trying to access a part of std_logic_vector using variables as indexes.
The following process gets a shift_val result from a function and then uses it to calculate the indexes to extract the 6-bit data we need in shift_data_in_s
I am getting a simulation error on the last line:
shift_data_in_s <= data_in_e(to_integer(unsigned(msb_pos)) downto to_integer(unsigned(lsb_pos)))
saying "Array size of 6 on LHS does not match the array size of 1 on
RHS"
I thought the initialization on lsb_pos and msb_pos would solve this problem but it didnt... not sure how it gets the same value for both these variables, if I am explicitly computing them by subtracting the same value from different constants.
signal shift_val_s : std_logic_vector(3 downto 0);
signal shift_data_in_s : std_logic_vector(5 downto 0);
shift_in_proc : process( data_in, num_zeros_s )
variable data_in_e : std_logic_vector(15 downto 0);
variable msb_pos : std_logic_vector(4 downto 0) := "01110";
variable lsb_pos : std_logic_vector(4 downto 0) := "01001";
begin
data_in_e := data_in & zeros_f(16 - data_in'length);
shift_val_s <= some_function(data_in_e);
if ( to_integer(unsigned(shift_val)) >= 12) then
-- all zeros
shift_data_in_s <= ( others => '0');
else
-- we need only 6 significant bits from the data,
-- msb_pos <= 15 - num_zeros -1;
msb_pos := std_logic_vector( "01110" - unsigned(('0' & shift_val_s)));
-- lsb_pos <= 15 - num_zeros -6;
lsb_pos := std_logic_vector("01001" - unsigned(('0' & shift_val_s)));
if ( lsb_pos(4) = '1') then -- if -ve
shift_data_in_s <= data_in_e(to_integer(unsigned(msb_pos)) downto 0) & zeros_f( to_integer(unsigned(neg_f(lsb_pos))));
else
shift_data_in_s <= data_in_e(to_integer(unsigned(msb_pos)) downto to_integer(unsigned(lsb_pos)));
end if;
end if ; end process shift_in_proc;

The most likely explanation is that msb_pos and lsb_pos contain a metavalue (ie. non-01HL data), presumably because data_in is invalid. The to_integer calls would then both return 0, giving you a range of 1, not 6. In any event, you can find out quickly using your simulator.
EDIT
Quick fix, as per your comment: make sure that some_function always returns a non-metavalue 4-bit vector. There are lots of ways to do this, but you could simply do:
fixed_answer <= to_01(metaval_answer); -- remove metavals
There's a to_01 in numeric_std, which takes an unsigned and returns an unsigned. By default, metavalues are converted to zero. You'll still get the wrong answer at the breginning of simulation, but at least the sim will carry on.

The value of your variable lsb_pos is dependent on shift_val_s, which is itself dependent on some_function - the code for which you have not provided. So it is not possible for anyone here to directly diagnose the problem.
Incidentally your code would be easier to read if you use integer variables, e.g.:
variable msb_pos : integer range 0 to 31 := 14;
variable lsb_pos : integer range 0 to 31 := 9;
The last line then becomes:
shift_data_in_s <= data_in_e(msb_pos downto lsb_pos);
If your some_function returns an integer you can calculate your msb_pos as such:
msb_pos := 14 - shift_val_s;
lsb_pos := 9 - shift_val_s;

Related

Input data is not being loaded into registers - issues only in post-synthesis timing simulation [VHDL][Vivado] (SOLVED)

What this is
I'm trying to create a simple FIR filter. What I'm going to present you may not exactly be a FIR filter as I'm gradually increasing complexity of my project for educational purpouses till it reaches desired functionality.
What it should be doing
Basically what it should be doing so far:
load data to registers after applying load = 1,
unload processed data (which is product of multiplication of samples with corresponding coefficients) after applying start = 1.
Where it fails
However from what I've noticed it fails to load data into registers. Seems to be working like a latch, as after load drops to 0, the last vector value at input port is being latched in the registers. But I may be wrong, it just appears to be working like this in simulation.
Pre- and post-synthesis functional simulation is working! Only the post-synthesis timing is failing to work as desired!
What I've tried
Adding DONT_TOUCH parameter to entity declaration in its .vhd file,
Adding kind of buffer (unsigned variable) after data_in port from which the data is being transfered to registers - but it did not even appear in schematic after synthesis, maybe the DONT_TOUCH did not work?
Simulations pictures
Pre-synth functional - https://imgur.com/0TaNQyn
Post-synth timing - https://imgur.com/mEOv67t
Program
I'm using Vivado 2020.2 webpack
Testbench
Testbench code here: https://pastebin.pl/view/d2f9a4ad
Main code
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
entity fir is
Port (
clk: in std_logic;
data_in: in unsigned(7 downto 0);
data_out: out unsigned(7 downto 0);
en: in std_logic;
load: in std_logic;
start: in std_logic;
reset: in std_logic
);
end fir;
architecture Behavioral of fir is
-- type coeff_array is array (0 to 7) of integer range 0 to 255;
constant reg_size: integer := 8;
constant filter_order: integer := 7;
type samples_reg is array (0 to reg_size-1) of unsigned(7 downto 0);
type coeffs_reg is array (0 to filter_order) of unsigned(7 downto 0);
begin
process(clk, reset)
-- variable coeffs: coeff_array := (0,0,0,0,0,0,0,0);
--variable b0: unsigned(7 downto 0) := 8D"0";
variable b0: unsigned(7 downto 0) := to_unsigned(1,8);
variable b1: unsigned(7 downto 0) := to_unsigned(2,8);
variable b2: unsigned(7 downto 0) := to_unsigned(3,8);
variable b3: unsigned(7 downto 0) := to_unsigned(4,8);
variable b4: unsigned(7 downto 0) := to_unsigned(5,8);
variable b5: unsigned(7 downto 0) := to_unsigned(6,8);
variable b6: unsigned(7 downto 0) := to_unsigned(7,8);
variable b7: unsigned(7 downto 0) := to_unsigned(8,8);
variable i: integer range 0 to reg_size := 0;
variable samples: samples_reg := (others => (others => '0'));
variable coeffs: coeffs_reg := (b0,b1,b2,b3,b4,b5,b6,b7);
variable data_processed: unsigned(15 downto 0) := (others => '0');
-- variable reg_element:
-- signal s1 : signed(47 downto 0) := 48D"46137344123";
begin
if reset = '1' then
-- data_out <= (others => '0');
samples := (others => (others => '0'));
data_processed := (others => '0');
i := 0;
-- synch part
elsif rising_edge(clk) and en = '1' then
samples := samples;
-- loading data
if load = '1' then
samples(i) := data_in;
i := i+1;
else null;
end if;
-- deloading data
if start = '1' then
data_processed := samples(i)*coeffs(i);
i := i+1;
else null;
end if;
-- reset counter after overflow
if(i = reg_size) then
i := 0;
else null;
end if;
-- reset counter if no data is being transferred
if load = '0' and start = '0' then
i := 0;
data_processed := (others => '0');
else null;
end if;
end if;
data_out <= data_processed(7 downto 0);
end process;
end Behavioral;
Other info
I just noticed that I'm holding load = 1 for one excessive cycle, which is why the highest number appears first.
The coefficients are: 1, 2, 3, 4, 5, 6, 7, 8.
In post-synth simulations after peeking into UUT, I've noticed that the samples registers are not loading the data (except for the last one, as I've mentioned earlier), the i is incrementing and the rest appears to be working properly.
I'll be happy to hear about some improvements for my code in addition to the problem solution!
Turns out in timing simulation I had to give the device at least 100 ns of warm-up time.
Seems like the timing simulations takes some factors related to device start-up into consideration -- anyway, I'm not sure about the explanation but I am sure of the above solution.
I have rephrased the title so others can find this post by searching for core problem in this case.
Good luck :)

16bit to bcd conversion

I'm trying to make a 16bit to BCD conversion.
I have found this link for a 8 bit and I'm trying to convert it to 16 bits.
http://vhdlguru.blogspot.nl/2010/04/8-bit-binary-to-bcd-converter-double.html
I don't know what im doing wrong the rpm_1000 keeps changing and the rpm_100 stays at 4. Does anyone have a idea what i did wrong?
process (Hex_Display_Data)
variable i : integer:=0;
variable bcd : std_logic_vector(19 downto 0) := (others => '0');
variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;
begin
for i in 0 to 15 loop -- repeating 16 times.
bcd(19 downto 1) := bcd(18 downto 0); --shifting the bits.
bcd(0) := bint(15); -- shift bit in
bint(15 downto 1) := bint(14 downto 0); --removing msb
bint(0) :='0'; -- adding a '0'
if(i < 15 and bcd(3 downto 0) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(3 downto 0) := bcd(3 downto 0) + "0011";
end if;
if(i < 15 and bcd(7 downto 4) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(7 downto 4) := bcd(7 downto 4) + "0011";
end if;
if(i < 15 and bcd(11 downto 8) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(11 downto 8) := bcd(11 downto 8) + "0011";
end if;
if(i < 15 and bcd(15 downto 12) > "0100") then --add 3 if BCD digit is greater than 4.
bcd(15 downto 12) := bcd(15 downto 12) + "0011";
end if;
end loop;
rpm_1000 <= bcd(15 downto 12);
rpm_100 <= bcd(11 downto 8);
rpm_10 <= bcd(7 downto 4);
rpm_1 <= bcd(3 downto 0);
end process ;
Note four BCD digits can be wholly contained in 14 bits of input (your Hex_Display_Data) and unused bcd 'bits' (19 downto 16) will get eaten during synthesis along with all the add 3's that can't occur because their upper two bits are '0's (not > 4).
If you constrain your bcd value to 4 hex digits, and your loop iteration to 14 bits:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd is
port (
input: in std_logic_vector (15 downto 0);
ones: out std_logic_vector (3 downto 0);
tens: out std_logic_vector (3 downto 0);
hundreds: out std_logic_vector (3 downto 0);
thousands: out std_logic_vector (3 downto 0)
);
end entity;
architecture fum of bin2bcd is
alias Hex_Display_Data: std_logic_vector (15 downto 0) is input;
alias rpm_1: std_logic_vector (3 downto 0) is ones;
alias rpm_10: std_logic_vector (3 downto 0) is tens;
alias rpm_100: std_logic_vector (3 downto 0) is hundreds;
alias rpm_1000: std_logic_vector (3 downto 0) is thousands;
begin
process (Hex_Display_Data)
type fourbits is array (3 downto 0) of std_logic_vector(3 downto 0);
-- variable i : integer := 0; -- NOT USED
-- variable bcd : std_logic_vector(15 downto 0) := (others => '0');
variable bcd: std_logic_vector (15 downto 0);
-- variable bint : std_logic_vector(15 downto 0) := Hex_Display_Data;
variable bint: std_logic_vector (13 downto 0); -- SEE process body
begin
bcd := (others => '0'); -- ADDED for EVERY CONVERSION
bint := Hex_Display_Data (13 downto 0); -- ADDED for EVERY CONVERSION
for i in 0 to 13 loop
bcd(15 downto 1) := bcd(14 downto 0);
bcd(0) := bint(13);
bint(13 downto 1) := bint(12 downto 0);
bint(0) := '0';
if i < 13 and bcd(3 downto 0) > "0100" then
bcd(3 downto 0) :=
std_logic_vector (unsigned(bcd(3 downto 0)) + 3);
end if;
if i < 13 and bcd(7 downto 4) > "0100" then
bcd(7 downto 4) :=
std_logic_vector(unsigned(bcd(7 downto 4)) + 3);
end if;
if i < 13 and bcd(11 downto 8) > "0100" then
bcd(11 downto 8) :=
std_logic_vector(unsigned(bcd(11 downto 8)) + 3);
end if;
if i < 13 and bcd(15 downto 12) > "0100" then
bcd(11 downto 8) :=
std_logic_vector(unsigned(bcd(15 downto 12)) + 3);
end if;
end loop;
(rpm_1000, rpm_100, rpm_10, rpm_1) <=
fourbits'( bcd (15 downto 12), bcd (11 downto 8),
bcd ( 7 downto 4), bcd ( 3 downto 0) );
end process ;
end architecture;
Note the use of aliases to enable your names to be used in an existing otherwise compatible Minimal, Complete and Verifiable Example which your question did not provide.
Aggregate signal assignment is also taken from the original, your assignment to the individual digits should work just fine.
There are two changes besides limiting the conversion to 14 bits and the number of BCD digits to match the number of digits output.
The bcd and bint variables are now cleared every time the process is resumed (sensitive to updates to Hex_Display_Data). These were causing causing your otherwise unverifiable errors more than likely.
Extraneous parentheses have been removed.
You didn't supply context clauses. The code shown uses package numeric_std as opposed to the -2008 numeric_std_unsigned offering compatibility with earlier revisions of the standard while using IEEE authored packages.
You'll get something that works, provable with a testbench:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bin2bcd_tb is
end entity;
architecture foo of bin2bcd_tb is
signal input: std_logic_vector (15 downto 0) := (others => '0');
signal ones: std_logic_vector (3 downto 0);
signal tens: std_logic_vector (3 downto 0);
signal hundreds: std_logic_vector (3 downto 0);
signal thousands: std_logic_vector (3 downto 0);
begin
DUT:
entity work.bin2bcd
port map (
input => input,
ones => ones,
tens => tens,
hundreds => hundreds,
thousands => thousands
);
STIMULUS:
process
begin
for i in 0 to 1001 loop
wait for 20 ns;
input <= std_logic_vector(to_unsigned(9999 - i, 16));
end loop;
wait for 20 ns;
wait;
end process;
end architecture;
Some other stimulus scheme can be used to toggle BCD digit roll over of all four digits.
This testbench provides input values starting at 9999 and decrementing 1001 times to show all four digits transitioning:
I can easily be modified to prove every transition of every BCD digit.
In summary the errors you were encountering appear to have come from the difference in elaboration for variables in a subprogram, where bcd and bint would be dynamically elaborated and initialized every function call, and in the process where they would be only initialized once.
From examining Xilinx's User Guide 901 Vivado Design Suite User Guide, Synthesis (2015.3), Chapter 4: VHDL Support, Combinatorial Processes, case Statements, for-loop Statements, the for loop appears to be supported for synthesis and has been reported to be synthesis eligible in other double dabble questions on stackoverflow. The issue would be support for repetitive assignment to variables in repeated sequences of sequential statements, which should be supported. There are is at least one other double dabble question on stackoverflow where successful synthesis had been reported using such a for loop.
Note that constraining the input value you deal with to 14 bits doesn't detect the effects of larger binary numbers (> 9999) which your process does not otherwise do either providing only 4 BCD output digits. You could deal with that by checking if the input value is greater than 9999 (x"270F").
The + 3 represents 1 LUT depth in an FPGA (4 bit input, 4 bit output), there are some number of them layered in depth based on the size of the converted number (the range of i). Allowing time for conversion propagation through ADD3's is offset by the rate at which the display can be visually interpreted. If you updated Hex_Display_Data in the millisecond range you likely could not tell the difference visually.
Running the loop 16 times will cause the value in the BCD registers to be multiplied by 65536 (mod 100000) and added to the value in the binary registers. Say the value is 4000. Then 4000x65536 yields 44000. 44000x65536 yields 84000. 84000x65536 yields 24000. 24000x65536 yields 64000. And 64000x65536 yields 4000.
To make the algorithm work, you must start out by clearing the BCD registers. It also wouldn't hurt to fix the comment about how many times your loop runs.
Incidentally, a practical implementation of a binary to BCD converter should generally accept a clock input, and perform one step for each active clock edge. If your VHDL is running entirely in simulation the complexity of the resulting logic won't matter, but trying to perform everything at once in real hardware will be rather expensive. By contrast, the hardware to do a simple shift of the binary number and a multiply-by-two of the BCD number will be much simpler. Note that if you do things "all at once", the most significant bit of the output will depend upon the second-least-significant bit of the input, meaning the input signal will have to propagate through all the logic in one step. By contrast, if you shift by one bit per clock cycle, each bit of the output will depend only upon at most four bits of the input (since each digit will be in the range 0-9 before the adjustment phase, adding 3 will never cause a carry out).
Also, the "double dabble" algorithm requires that the adjustment be performed before the BCD shifts, but it looks as though the code is performing the adjustment after. Doing the adjustment after is fine if one looks at bit
ranges 16..13, 12..9, 8..5, and 4..1 rather than 15..12, etc. Alternatively, one could specify that the value of bits 19..17 should be the value of bits 18..16, the value of bits 16..13 should be either the value of bits 15..12 (if less than 5) or the value of bits 15..12, plus three (if greater), etc. Such a formulation would set the value of each bit in exactly one place, which would make it easier to see how it should be rendered into hardware.

Output is always zeros (quotient and remainder) in divider code VHDL

Output is always zeros (quotient and remainder) in the code shown below.
Even if I assign value of b to remainder,it is giving 0. I have checked for many times but I am not able to understand what the issue is. While compiling, it is showing 2 warnings:
- Initial value of "b" depends on value of signal "divisor".
What is the problem?
-- DIVIDER
library ieee;
use ieee.numeric_bit.all;
entity unsigned_divider is
port(
-- the two inputs
dividend: in bit_vector(15 downto 0);
divisor : in bit_vector(15 downto 0);
-- the two outputs
quotient : out bit_vector(15 downto 0);
remainder : out bit_vector(15 downto 0)
);
end entity unsigned_divider;
architecture behave of unsigned_divider is
begin
process
variable a : bit_vector(15 downto 0):=dividend;
variable b : bit_vector(15 downto 0):=divisor;
variable p : bit_vector(15 downto 0):= (others => '0');
variable i : integer:=0;
begin
for i in 0 to 15 loop
p(15 downto 1) := p(14 downto 0);
p(0) := a(15);
a(15 downto 1) := a(14 downto 0);
p := bit_vector(unsigned(p) - unsigned(b));
if(p(15) ='1') then
a(0) :='0';
p := bit_vector(unsigned(p) + unsigned(b));
else
a(0) :='1';
end if;
wait for 1 ns;
end loop;
quotient <= a after 1 ns;
remainder <= p after 1 ns;
end process;
end behave;
You should have explicit assignments to the variables a and b inside the process statement part (as sequential signal assignments). The declarations:
variable a : bit_vector(15 downto 0):=dividend;
variable b : bit_vector(15 downto 0):=divisor;
Should be:
variable a : bit_vector(15 downto 0);
variable b : bit_vector(15 downto 0);
And in the process statement part (following the begin in the process):
a := dividend;
b := divisor;
These overcome the issue natipar mentions, that the values are only assigned to a and b during initialization.
Further should you desire to have a 1 ns delay you should have an explicit wait statement as the last sequential statement of the process statement process statement part:
wait on dividend, divisor;
These make your process statement look something like this (with indentation added):
process
variable a : bit_vector(15 downto 0); -- := dividend;
variable b : bit_vector(15 downto 0); -- := divisor;
variable p : bit_vector(15 downto 0) := (others => '0');
variable i : integer := 0;
begin
a := dividend;
b := divisor;
for i in 0 to 15 loop
p(15 downto 1) := p(14 downto 0);
p(0) := a(15);
a(15 downto 1) := a(14 downto 0);
p := bit_vector(unsigned(p) - unsigned(b));
if p(15) = '1' then
a(0) :='0';
p := bit_vector(unsigned(p) + unsigned(b));
else
a(0) := '1';
end if;
wait for 1 ns;
end loop;
quotient <= a after 1 ns;
remainder <= p after 1 ns;
wait on dividend, divisor;
end process;
(Note the space between the numeric literal and the units, required by IEEE Std 1076-2008, 15.3 Lexical elements, separators and delimiters paragraph 4, the last sentence "At least one separator is required between an identifier or an abstract literal and an adjacent identifier or abstract literal.", despite Modelsim not requiring it).
Writing a simple testbench we find at least one error in your restoring division algorithm:
entity unsigned_divider_tb is
end entity;
architecture foo of unsigned_divider_tb is
signal dividend, divisor: bit_vector (15 downto 0) := (others => '0');
signal quotient, remainder: bit_vector (15 downto 0);
function to_string(inp: bit_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: bit_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(BIT'IMAGE(input_str(i)));
end loop;
return image_str;
end;
begin
DUT:
entity work.unsigned_divider
port map (
dividend,
divisor,
quotient,
remainder
);
MONITOR:
process (quotient, remainder)
begin
report "quotient = " & to_string (quotient) severity NOTE;
report "remainder = " & to_string (remainder) severity NOTE;
end process;
end architecture;
ghdl -a unsigned_divider.vhdl
ghdl -e unsigned_divider_tb
ghdl -r unsigned_divider_tb
unsigned_divider.vhdl:83:9:#0ms:(report note): quotient = 0000000000000000
unsigned_divider.vhdl:84:9:#0ms:(report note): remainder = 0000000000000000
unsigned_divider.vhdl:83:9:#17ns:(report note): quotient = 1111111111111111
unsigned_divider.vhdl:84:9:#17ns:(report note): remainder = 0000000000000000
(And a note on interpretation, the transactions reported at time 0 ms are the default assignments performed as a result of elaboration).
Your algorithm gives a wrong answer for division by 0.
Adding a stimulus process to the testbench:
STIMULUS:
process
begin
wait for 20 ns;
dividend <= x"ffff";
divisor <= x"000f";
end process;
Shows it can get the right answer too:
unsigned_divider.vhdl:83:9:#37ns:(report note): quotient = 0001000100010001
unsigned_divider.vhdl:84:9:#37ns:(report note): remainder = 0000000000000000
And with the testbench and added wait statements and assignments in the stimulus process you can explore further.
I've always been a fan of non-restoring division myself, because the adds or subtracts take a clock in a clocked divider.
Variable assignments take effect immediately; but the signal, at the moment of the creation of that variable, has no value, so you cannot expect the assignments
variable a : bit_vector(15 downto 0):=dividend;
variable b : bit_vector(15 downto 0):=divisor;
to work correctly. I'm a bit surprised that there are no complaints for the assignment to the variable a though. Perhaps it is your second warning. You should define the variables the way you do, but leave the assignment for later, in the begin segment of your process.
P.S. Also, you might want to change remainder <= p after 1ns; to remainder <= p after 1 ns;.

VHDL How to convert 32 bit variable to 4 x 8bit std_logic_vector?

I have a question which is probably in 2 parts:
I am using a (nominally 32 bit) integer variable which I would like to write to an 8 bit UART as 4 bytes (i.e., as binary data)
i.e. variable Count : integer range 0 to 2147483647;
How should I chop the 32 bit integer variable into 4 separate 8 bit std_logic_vectors as expected by my UART code, and how should I pass these to the UART one byte at a time ?
I am aware std_logic_vector(to_unsigned(Count, 32)) will convert the integer variable into a 32 bit std_logic_vector, but then what ? Should I create a 32 bit std_logic_vector, assign the converted Count value to it, then subdivide it using something like the following code ? I realise the following assumes the count variable does not change during the 4 clock cycles, and assumes the UART can accept a new byte every clock cycle, and lacks any means of re-triggering the 4 byte transmit cycle, but am I on the right track here, or is there a better way ?
variable CountOut : std_logic_vector(31 downto 0);
process (clock)
variable Index : integer range 0 to 4 := 0;
begin
if rising_edge(clock) then
CountOut <= std_logic_vector(to_unsigned(Count, 32);
if (Index = 0) then
UartData(7 downto 0) <= CountOut(31 downto 24);
Index := 1;
elsif (Index = 1) then
UartData(7 downto 0) <= CountOut(23 downto 16);
Index := 2;
elsif (Index = 2) then
UartData(7 downto 0) <= CountOut(15 downto 8);
Index := 3;
elsif (Index =31) then
UartData(7 downto 0) <= CountOut(7 downto 0);
Index := 4;
else
Index := Index;
end if;
end if;
end process;
Any comments or recommendations would be appreciated.
Thanks,
MAI-AU.
You seem to be on the right track. I believe there are two basic solutions to this problem:
Register the output value as a 32-bit vector, and use different ranges for each output operation (as you did in your code example)
Register the output value as a 32-bit vector, and shift this value 8 bits at a time after each output operation. This way you can use the same range in all operations. The code below should give you an idea:
process (clock)
variable Index: integer range 0 to 4 := 0;
begin
if rising_edge(clock) then
if (Index = 0) then
CountOut <= std_logic_vector(to_unsigned(Count, 32));
Index := Index + 1;
elsif (Index < 4) then
UartData <= CountOut(31 downto 24);
CountOut <= CountOut sll 8;
Index := Index + 1;
end if;
end if;
end process;
Also, please check your assignments, in your example CountOut is declared as a variable but is assigned to as a signal.
There's nothing wrong with the code you've shown. You can do something to separate the the assignment to UartData using Index to allow a loop.
library ieee;
use ieee.std_logic_1164.all;
entity union is
end entity;
architecture foo of union is
type union32 is array (integer range 1 to 4) of std_logic_vector(7 downto 0);
signal UartData: std_logic_vector(7 downto 0);
begin
TEST:
process
variable quad: union32;
constant fourbytes: std_logic_vector(31 downto 0) := X"deadbeef";
begin
quad := union32'(fourbytes(31 downto 24), fourbytes(23 downto 16),
fourbytes(15 downto 8),fourbytes(7 downto 0));
for i in union32'RANGE loop
wait for 9.6 us;
UartData <= Quad(i);
end loop;
wait for 9.6 us; -- to display the last byte
wait; -- one ping only
end process;
end architecture;
Or use a type conversion function to hide complexity:
library ieee;
use ieee.std_logic_1164.all;
entity union is
type union32 is array (integer range 1 to 4) of std_logic_vector(7 downto 0);
end entity;
architecture fee of union is
signal UartData: std_logic_vector(7 downto 0);
function toquad (inp: std_logic_vector(31 downto 0)) return union32 is
begin
return union32'(inp(31 downto 24), inp(23 downto 16),
inp(15 downto 8), inp( 7 downto 0));
end function;
begin
TEST:
process
variable quad: union32;
constant fourbytes: std_logic_vector(31 downto 0) := X"deadbeef";
begin
quad := toquad (fourbytes);
for i in union32'RANGE loop
wait for 9.6 us;
UartData <= Quad(i);
end loop;
wait for 9.6 us; -- to display the last byte
wait; -- one ping only
end process;
end architecture;
And gives the same answer.

Issues with indexing arrays in VHDL

I have an assignment to create a simple microprocessor in VHDL. My code looks like this
architecture Behavioral of uc is
type instruction_t is array (255 downto 0) of std_logic_vector (15 downto 0);
constant LOAD : std_logic_vector(7 downto 0) :=x"01";
--some more instruction codes defined
signal PC : std_logic_vector (7 downto 0); -- program counter
signal cur_inst : std_logic_vector (15 downto 0);
constant ROM :
instruction_t :=
(
(LOAD & x"07"),
(ADD & x"05"),
-- some more code goes here
others => x"0000"
);
begin
process (CLK, RESET) is
begin
if RESET = '1' then
-- do stuff
elsif rising_edge(CLK) then
cur_inst <= ROM(conv_integer(PC));
PC <= PC + 1;
-- some other stuff
end if;
end process;
end Behavioral;
The problem I have is with this part:
cur_inst <= ROM(conv_integer(PC));
because simply nothing happens - cur_inst is always zero. I tried using
cur_inst <= ROM(to_integer(unsigned(PC));
but result is the same - I get nothing. PC is incremented properly, but I cannot read anything from ROM array. I also tried defining PC as unsigned or integer, but result is the same. What am I doing wrong?
Since you are defining instruction_t as an array(255 downto 0), initializing the array may be occuring in the opposite order that you intended.
(LOAD & x"07") will be assigned to ROM(255), (ADD & x"05") will be assigned to ROM(254), etc.
Define the type instruction_t as an array (0 to 255) to avoid this problem.
Another way of fixing the problem would have been to bind your instructions to the specific addresses you wanted, instead of just expecting it to happen : for that, use named association and write
constant ROM :
instruction_t :=
(
0 => (LOAD & x"07"),
1 => (ADD & x"05"),
-- some more code goes here
others => x"0000"
);

Resources