"Serialize" VHDL record - serialization

Suppose I have the following type definition which relies on constants to indicate vector length of the record members:
type point_t is record
x: std_logic_vector(X_WIDTH-1 downto 0);
y: std_logic_vector(Y_WIDTH-1 downto 0);
end record;
I would like to convert these kind of records into std_logic_vectors to put them into, say, a FIFO. Currently I am using the following code:
PROCEDURE encodepoint(signal pnt: in point_t;
signal d: out std_logic_vector(POINT_ENC_WIDTH-1 downto 0)) is
variable top: integer := 0;
begin
top := X_WIDTH-1;
d(top downto 0) <= pnt.x;
top := top + Y_WIDTH;
d(top downto top-X_WIDTH+1) <= sl.y;
d(d'left downto top+1) <= (others => '0');
end;
This code is suboptimal in many ways. For example it requires me to always correctly set POINT_ENC_WIDTH to a value that is big enough to allow d to hold the whole serialized record. It relies on the programmer to do very mechanical work. For example for every member of the record, say x, X_WIDTH appears twice in the code, once in direct connection with x and once in connection with the next member, y. This get tedious quickly. If I change the definition of the record by adding additional fields, I have to update both the serializing and the (very similar) deserializing code, and I may just forget this. When I remove fields, at least the compiler complains.
Thus this leads me to my question: Is there a simple, automated or at least quasi-automated way to convert VHDL records into std_logic_vectors without having to resort to manually written serializing/unserializing code? It is not important for me to know the specific encoding, as I am using the records internally and the final output format is clearly specified and will be implemented manually.

Can't you just write this:
d <= pnt.x & pnt.y;

While there is currently no official automated way of converting records to vectors (and vice-versa), it is a very common requirement. You have 2 options:
Define your own to_vector and from_vector functions for every record type (tedious)
Autogenerate packages containing above type conversions (difficult / error prone)
Tedious and repetitive tasks that motivate you to write a script to generate code are an indication of a deficiency in the language itself. You can change this by taking an active role in the IEEE working-group and influence the next version of the VHDL standard.

I typically define conversion functions in a package along with the record.
In your case, something like:
function point2slv (pnt : point_t) return std_logic_vector is
variable slv : std_logic_vector(X_WIDTH + Y_WIDTH - 1 downto 0);
begin
slv := pnt.x & pnt.y;
return slv;
end;
function slv2point (slv : std_logic_vector) return point_t is
variable pnt : point_t;
begin
pnt.x := slv(X_WIDTH + Y_WIDTH - 1 downto Y_WIDTH);
pnt.y := slv(Y_WIDTH - 1 downto 0);
return pnt;
end;
NOTE:
Depending on what you're trying to do, you may wish to use pre-defined sizes on one side or the other, and conversion functions to pad/clip to natural lengths (ie: perhaps fit the X and Y values into 16 or 32 bit values). The unsigned type and resize function work well for this:
slv(31 downto 16):= std_logic_vector(resize(unsigned(pnt.x,16)));
slv(15 downto 0):= std_logic_vector(resize(unsigned(pnt.7,16)));

Taken from discussion here
One reasonable way to do this, with large records is to define the ranges ahead of time like this:
type t_SPI_DATA_PORT is record
Data_Size_Minus1: std_ulogic_vector(31 downto 28);
Done: std_ulogic_vector(27 downto 27);
Rx_Wait_Timeout: std_ulogic_vector(26 downto 26);
Rx_Wait_On_Miso: std_ulogic_vector(25 downto 25);
Sclk_Select: std_ulogic_vector(24 downto 24);
Reserved: std_ulogic_vector(23 downto 20);
Hold_Cs: std_ulogic_vector(19 downto 19);
Cpha: std_ulogic_vector(18 downto 17);
Cpol: std_ulogic_vector(16 downto 16);
Data: std_ulogic_vector(15 downto 0);
end record;
Then the conversion functions look like this:
function To_Std_ULogic_Vector(L : t_SPI_DATA_PORT) return
std_ulogic_vector is
variable RetVal: std_ulogic_vector(31 downto 0);
begin
RetVal := (others => '0');
RetVal(L.Data_Size_Minus1'range) := L.Data_Size_Minus1;
RetVal(L.Done'range) := L.Done;
RetVal(L.Rx_Wait_Timeout'range) := L.Rx_Wait_Timeout;
RetVal(L.Sclk_Select'range) := L.Sclk_Select;
RetVal(L.Reserved'range) := L.Reserved;
RetVal(L.Rx_Wait_On_Miso'range) := L.Rx_Wait_On_Miso;
RetVal(L.Hold_Cs'range) := L.Hold_Cs;
RetVal(L.Cpha'range) := L.Cpha;
RetVal(L.Cpol'range) := L.Cpol;
RetVal(L.Data'range) := L.Data;
return(RetVal);
end To_Std_ULogic_Vector;
function From_Std_ULogic_Vector(L : std_ulogic_vector) return
t_SPI_DATA_PORT is
variable RetVal: t_SPI_DATA_PORT;
variable Lx: std_ulogic_vector(L'length - 1 downto 0);
begin
Lx := L;
RetVal.Data_Size_Minus1 := Lx(RetVal.Data_Size_Minus1'range);
RetVal.Done := Lx(RetVal.Done'range);
RetVal.Rx_Wait_Timeout := Lx(RetVal.Rx_Wait_Timeout'range);
RetVal.Sclk_Select := Lx(RetVal.Sclk_Select'range);
RetVal.Reserved := Lx(RetVal.Reserved'range);
RetVal.Rx_Wait_On_Miso := Lx(RetVal.Rx_Wait_On_Miso'range);
RetVal.Hold_Cs := Lx(RetVal.Hold_Cs'range);
RetVal.Cpha := Lx(RetVal.Cpha'range);
RetVal.Cpol := Lx(RetVal.Cpol'range);
RetVal.Data := Lx(RetVal.Data'range);
return(RetVal);
end From_Std_ULogic_Vector;

I have prepared a script which automatically generates the VHDL package for conversions between the user defined record type and the std_logic_vector type.
The sources of this script are published as PUBLIC DOMAIN in the alt.sources group.
You can see http://groups.google.com/group/alt.sources/browse_frm/thread/53ea61208013e9d1 or look for topic "Script to generate VHDL package for conversion between the record type and std_logic_vector"
If you want to unpack the archive from the Google archive, remember to select "show original" option. Otherwise the indendation of the Python source will be damaged.

I did another try at record serialization. I believe my method is a bit more robust. You still need to create function for every record type but you do not need to mention ranges.
Lets say you need to serialize type_a using my package:
type type_a is record
a : std_logic_vector(15 downto 0);
b : std_logic_vector(31 downto 0);
c : std_logic_vector(7 downto 0);
d : std_logic_vector(7 downto 0);
end record type_a;
constant type_a_width : integer := 64;
Define two functions like this:
use work.SERIALIZE_PKG.all;
function serialize (
input : type_a)
return std_logic_vector is
variable ser : serializer_t(type_a_width-1 downto 0);
variable r : std_logic_vector(type_a_width-1 downto 0);
begin -- function serialize_detectorCacheLine_t
serialize_init(ser);
serialize(ser, input.a);
serialize(ser, input.b);
serialize(ser, input.c);
serialize(ser, input.d);
r := serialize_get(ser);
return r;
end function serialize;
function deserialize (
input : std_logic_vector)
return type_a is
variable ser : serializer_t(type_a_width-1 downto 0);
variable r : type_a;
begin -- function serialize_detectorCacheLine_t
ser := serialize_set(input);
deserialize(ser, r.a);
deserialize(ser, r.b);
deserialize(ser, r.c);
deserialize(ser, r.d);
return r;
end function deserialize;
And then you can use it in code like this:
signal type_a_ser : std_logic_vector(type_a_width-1 downto 0) := (others => '0');
signal type_a_in : type_a;
signal type_a_out : type_a;
....
type_a_ser <= serialize(type_a_in);
type_a_out <= deserialize(type_a_ser);
I posted my code and example of more complex types (nested records etc) at: https://github.com/gitmodimo/vhdl-serialize

Related

VHDL password program with DE2-board

Summary:
I'm trying to make a password system in VHDL with the DE2 Altera board. SW 0 to 7 is the combination lock, LEDR 0 to 7 shows the current code and signal 'code' stores the combination. When the switches match the code you have the option to change the code by holding down KEY(1).
Problem:
The code works as it should, only the starter code is not what's expected. It should be: "01010101" as shown in the signal; but it comes out as "01111111". I suspect the program enters the if-statement on startup, but I don't see how that's possible, seeing as 'code' and SW should't be equal.
What am I missing?
Here is the code:
library IEEE;
use IEEE.std_logic_1164.all;
entity pass_sys is
port(
SW : in std_logic_vector(7 downto 0);
KEY : in std_logic_vector(3 downto 0);
LEDR : out std_logic_vector(17 downto 0);
LEDG : out std_logic_vector(17 downto 0)
);
end pass_sys;
architecture func of pass_sys is
signal code : std_logic_vector(7 downto 0) := "01010101"; --start code
begin
process(SW)
begin
LEDR(7 downto 0)<=code;
if (SW = code) then
LEDG(0)<='1';
LEDG(1)<=not KEY(1);
if (KEY(1) = '0') then
code<=SW;
end if;
else
LEDG(0)<='0';
end if;
end process;
end func;
I assume your problem happens on your board, not in simulation. If I'm wrong, my answer is not the one you expect.
This initialization way is usefull only in simulation :
signal code : std_logic_vector(7 downto 0) := "01010101"; --start code
Synthesis will not consider your initialization value (That's why I discourage you to use this, except in test bench). If you want to initialize a signal, I advice to use a reset.
Notes :
You should put KEY in sensitivity list and put this line out of your process :
LEDR(7 downto 0)<=code;
Your process infers latches, it's not forbidden but you must be careful with this
EDIT : How to add a reset
library IEEE;
use IEEE.std_logic_1164.all;
entity pass_sys is
port(
RST : in std_logic;
SW : in std_logic_vector(7 downto 0);
KEY : in std_logic_vector(3 downto 0);
LEDR : out std_logic_vector(17 downto 0);
LEDG : out std_logic_vector(17 downto 0)
);
end pass_sys;
architecture func of pass_sys is
signal code : std_logic_vector(7 downto 0);
begin
LEDR(7 downto 0)<=code;
process(SW, code, KEY)
begin
if RST = '1' then
LEDG <= (others => '0');
code <= "01010101";
elsif (SW = code) then
LEDG(0)<='1';
LEDG(1)<=not KEY(1);
if (KEY(1) = '0') then
code<=SW;
end if;
else
LEDG(0)<='0';
end if;
end process;
end func;
The pin RST of your component could be connected to an analogic signal of you card (POWER_GOOD, ALIM_ON, DONE, ...) or to a pll_locked signal of a PLL if you use it.

Why the INOUT doesn't work?

I am making a circuit that handles read and write operations to some registers and uses a single bus to transfer data between registers, the problem is that when reading from bus (a register is reading from bus) it works well, but when trying to assign a value in a register it is not working. Note that if i used a signal to write to it will work !!!
My Code:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
-- Entity: Circuit
-- Description: Organizes read and write operation to the bus
-- n is the size of word in a register, default is 16
-- m is the number of selection lines in the decoder, so 2 ^ m
-- is the number of registers in the cicuit
-- data_bus: the bus used to transfer data
-- reg_read: input to a decoder determines which register to read from bus.
-- reg_write: input to a decoder determines which register to write to bus.
-- read: read signal
-- write: write signal
-- Clk: clock
-- Rst: Reset
ENTITY circuit IS
GENERIC( n : integer := 16;
m : integer := 2);
PORT(data_bus : INOUT STD_LOGIC_VECTOR(n-1 DOWNTO 0);
reg_read, reg_write : IN STD_LOGIC_VECTOR(m-1 DOWNTO 0);
read, write, Clk, Rst : IN STD_LOGIC);
END circuit;
ARCHITECTURE circuit_arch OF circuit IS
-- Tristate buffers
COMPONENT tsb IS
GENERIC ( n : integer := 16);
PORT ( E : IN STD_LOGIC;
Input : IN STD_LOGIC_VECTOR (n-1 DOWNTO 0);
Output : OUT STD_LOGIC_VECTOR (n-1 DOWNTO 0));
END COMPONENT;
-- Registers
COMPONENT ndff IS
GENERIC ( n : integer := 16);
PORT( Clk,Rst,E : in STD_LOGIC;
d : IN STD_LOGIC_VECTOR(n-1 dOWNTO 0);
output : OUT STD_LOGIC_VECTOR(n-1 dOWNTO 0));
END COMPONENT;
-- Decoders
COMPONENT nDecoder IS
GENERIC ( n : integer := 4);
PORT(E : IN std_logic;
S : IN STD_LOGIC_VECTOR( n-1 DOWNTO 0);
output : OUT std_logic_vector(2 ** n - 1 DOWNTO 0));
END COMPONENT;
TYPE output IS ARRAY (0 TO (2 ** m) - 1) OF STD_LOGIC_VECTOR (n-1 DOWNTO 0);
SIGNAL read_dec, write_dec : STD_LOGIC_VECTOR(2 ** m - 1 DOWNTO 0);
SIGNAL regs_out : output;
SIGNAL test : STD_LOGIC_VECTOR(n-1 downto 0);
BEGIN
-- Generate decoders
dec1: nDecoder GENERIC MAP(m) PORT MAP(read, reg_read, read_dec);
dec2: nDecoder GENERIC MAP(m) PORT MAP(write, reg_write, write_dec);
-- Generate registers
LOOP1: FOR i IN 0 TO (2 ** m) - 1 GENERATE
lbl1: ndff GENERIC MAP(n) PORT MAP(Clk, Rst,read_dec(i),data_bus, regs_out(i));
END GENERATE;
-- Generate tristate buffers
LOOP2: FOR j IN 0 TO (2 ** m) - 1 GENERATE
lbl2: tsb GENERIC MAP(n) PORT MAP(write_dec(j), regs_out(j), data_bus);
END GENERATE;
END circuit_arch;
If you look at lbl1 in the generate statement you'll find the portmap:
lbl1: ndff generic map(n) port map(clk, rst,read_dec(i),data_bus, regs_out(i));
is positionally associative. While the port declaration reflected in the component declaration shows the order:
port( clk,rst,e : in std_logic;
d : in std_logic_vector(n-1 downto 0);
output : out std_logic_vector(n-1 downto 0));
Showing that read_dec(i) is the register load enable.
And the read buffers:
-- generate tristate buffers
loop2: for j in 0 to integer(2 ** m) - 1 generate
lbl2: tsb generic map(n) port map(write_dec(j), regs_out(j), data_bus);
end generate;
Show write_dec(j).
And examining the decodes for generating them shows:
-- generate decoders
dec1: ndecoder generic map(m) port map(read, reg_read, read_dec);
dec2: ndecoder generic map(m) port map(write, reg_write, write_dec);
read corresponds to read_dec and write corresponds to write_dec.
It certainly looks like you have the enables reversed for the registers loads and register output buffer enables.
There could be more, but without a MVCE someone answering can't get beyond basic eyeballing and analyzing.
And the reason Paebbels asked about target implementation is that for all practical purposes tristate internal buffers are generally restricted to ASIC implementations.

VHDL small error when using a conditional signal assignment (when...else)

I'm currently working on a component that will perform addition or subtraction, depending on the user input. Right now, I am working on a process that handles the assignment of values to the internal signals which will be used by the internal components I am using. One problem that comes up is in the line when I'm assigning b_in with either the input b or the 2's complement of the input b. Two errors show up:
Error: COMP96_0015: addsub_16.vhd : (85, 17): ';' expected.
Error: COMP96_0046: addsub_16.vhd : (85, 41): Sequential statement expected.
The errors all reference to the line
b_in <= (b) when add_sub = '0' else (b_2scomp);
However when I placed this outside the process, no error occurred; only when it's inside the process. Can someone please help me why this is and what I can do to solve it?
In addition, I know that normally port mapping is done between the architecture declaration and the begin statement of the architecture. The reason I placed them after the process is because I needed to make sure that b_in has the right signal before the other components can use it. I don't know if this is the right way to do it, but I hope it is. This is just in case you guys are wondering why I'm dong it like this. Thanks
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.STD_LOGIC_ARITH.all;
entity addsub_16 is
port(
c_in : in STD_LOGIC;
enable : in std_logic;
reset : in std_logic;
clk : in std_logic;
add_sub : in STD_LOGIC;
a : in STD_LOGIC_VECTOR(15 downto 0);
b : in STD_LOGIC_VECTOR(15 downto 0);
c_out : out STD_LOGIC;
result : out STD_LOGIC_VECTOR(15 downto 0)
);
end addsub_16;
architecture addsub_16 of addsub_16 is
--Signal declarations to hold internal vectors a, b g, p, and carry
signal a_in : std_logic_vector(15 downto 0); --Holds input a
signal b_in : std_logic_vector(15 downto 0); --Holds input b if add_sub = 0. Otherwise, holds b_2scomp
signal b_2scomp : std_logic_vector(15 downto 0); --Holds the 2s complement of b
signal prop_in : std_logic_vector(15 downto 0); --Holds the propagate signals from CLAs
signal gen_in : std_logic_vector(15 downto 0); --Holds the generate signals from CLAs
signal carry_in : std_logic_vector(15 downto 0); --Holds the carry signal from carry_logic
signal temp_result : std_logic_vector(15 downto 0); --Holds the temporary result to be driven out
--Component declarations
component cla_4bit
port (
a, b : in std_logic_vector(3 downto 0);
gen, prop : out std_logic_vector(3 downto 0)
);
end component;
component carry_logic
port (
g, p : in std_logic_vector(15 downto 0);
c_in : in std_logic;
carry : out std_logic_vector(15 downto 0);
c_out : out std_logic
);
end component;
--Actual behavior of module
begin
--b_in <= (b) when add_sub = '0' else (b_2scomp);
process (clk, reset)
begin
if reset = '0' then --At reset, everything is 0
a_in <= (others => '0');
b_in <= (others => '0');
b_2scomp <= (others => '0');
temp_result <= (others => '0');
elsif (rising_edge(clk)) then --Read in data to components on rising edge
if enable = '1' then --Only if enable is on
a_in <= a;
b_2scomp <= ((not b) + '1');
b_in <= (b) when add_sub = '0' else (b_2scomp);
end if;
elsif (falling_edge(clk)) then --Drive out values on falling edge
for i in 0 to 15 loop
temp_result(i) <= a_in(i) xor b_in(i) xor carry_in(i);
end loop;
result <= temp_result;
end if;
end process;
--portmapping of the components here. I don't think it'd be necessary to include them, but let me know if they are needed.
The ternary operator .. when .. else .. is not allowed inside a process block prior to VHDL-2008.
Solution 1: Write an ordinary if .. then .. else .. end if statement
Solution 2: Enable VHDL-2008 support in your tool chain
Solution 3: Write a function, lets say ite (if-then-else), which performs the ternary operation.

VHDL - init std_logic_vector array from HEX file

I have simple "RAM" implemented as:
type memory_array is array(31 downto 0) of std_logic_vector(7 downto 0);
signal ram : memory_array;
I would like to init it's content from HEX file. I wonder about reading the file like:
ram_init: process
file file_ptr : text;
variable line_text : string(1 to 14);
variable line_num : line;
variable lines_read : integer := 0;
variable char : character;
variable tmp_hexnum : string(1 to 2);
begin
file_open(file_ptr,"../RAM.HEX",READ_MODE);
while (not endfile(file_ptr)) loop
readline (file_ptr,line_num);
READ (line_num,line_text);
if (lines_read < 32) then
tmp_hexnum := line_text(10 to 11);
-- ram(lines_read) <= tmp_hexnum;
lines_read := lines_read + 1;
wait for 10 ns;
end if;
end loop;
file_close(file_ptr);
wait;
end process;
The problem is (if this code above would works, which I don't even know), how to convert the tmp_hexnum string to std_logic_vector.
Please have patience with me, VHDL beginner.
The first mistake is to use a process : if you attempt to synthesise the design, the process won't do anything until the design is built and running; which is far too late to read a file!
Instead, wrap the init code in a function, and use that to initialise the memory
signal ram : memory_array := my_ram_init(filename => "../RAM.HEX");
This will work in simulation, and many synthesis tools will infer a RAM and initialise it correctly. If you declared a constant instead of a signal, this would create a ROM instead of a RAM.
Anyway the function looks a bit like
function my_ram_init(filename : string) return memory_array is
variable temp : memory_array;
-- other variables
begin
file_open(...);
-- you have a good handle on the function body
file_close(...);
return temp;
end function;
leaving you with the original problem :
temp(lines_read) <= to_slv(tmp_hexnum);
writing the to_slv function. There ought to be a standard library of these, but for some reason there isn't a universally accepted one. So, here's a start...
function to_slv (tmp_hexnum : string) return std_logic_vector is
variable temp : std_logic_vector(7 downto 0);
variable digit : natural;
begin
for i in tmp_hexnum'range loop
case tmp_hexnum(i) is
when '0' to '9' =>
digit := Character'pos(tmp_hexnum(i)) - Character'pos('0');
when 'A' to 'F' =>
digit := Character'pos(tmp_hexnum(i)) - Character'pos('A') + 10;
when 'a' to 'f' =>
digit := Character'pos(tmp_hexnum(i)) - Character'pos('a') + 10;
when others => digit := 0;
end case;
temp(i*4+3 downto i*4) := std_logic_vector(to_unsigned(digit));
end loop;
return temp;
end function;
Converting a string of variable length to std_logic_vector with length as 4 *
length of string, can be done with the function below:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
...
-- Convert string to std_logic_vector, assuming characters in '0' to '9',
-- 'A' to 'F', or 'a' to 'f'.
function str_to_slv(str : string) return std_logic_vector is
alias str_norm : string(1 to str'length) is str;
variable char_v : character;
variable val_of_char_v : natural;
variable res_v : std_logic_vector(4 * str'length - 1 downto 0);
begin
for str_norm_idx in str_norm'range loop
char_v := str_norm(str_norm_idx);
case char_v is
when '0' to '9' => val_of_char_v := character'pos(char_v) - character'pos('0');
when 'A' to 'F' => val_of_char_v := character'pos(char_v) - character'pos('A') + 10;
when 'a' to 'f' => val_of_char_v := character'pos(char_v) - character'pos('a') + 10;
when others => report "str_to_slv: Invalid characters for convert" severity ERROR;
end case;
res_v(res_v'left - 4 * str_norm_idx + 4 downto res_v'left - 4 * str_norm_idx + 1) :=
std_logic_vector(to_unsigned(val_of_char_v, 4));
end loop;
return res_v;
end function;
Your (both) answers helped me a lot. But it seems not working.
function ram_init(filename : string) return memory_array is
variable temp : memory_array;
file file_ptr : text;
variable line_line : line;
variable line_text : string(1 to 14);
variable tmp_hexnum : string(1 to 2);
variable lines_read : integer := 0;
begin
file_open(file_ptr,filename,READ_MODE);
while (lines_read < 32 and not endfile(file_ptr)) loop
readline (file_ptr,line_line);
read (line_line,line_text);
tmp_hexnum := line_text(10 to 11);
temp(lines_read) := hex_to_bin(tmp_hexnum);
lines_read := lines_read + 1;
end loop;
file_close(file_ptr);
return temp;
end function;
signal ram : memory_array := ram_init(filename=>"../RAM.HEX");
If I set tmp_hexnum to e.g. "0A", it's OK, but reading from file do not fill the RAM.
Can you please check the file part for me, too?

Design of "simple" VHDL module still drives me mad

Thanks to all your input, I implemented your suggestions, however the problem remains the same. The result in simulation works fine, but the hardware
outputs something different. Just to briefly recap, I have two ctrl signals that determine the behaviour of the entity:
GET (ctrl = "00000000") sets register tx to input of op1
SH1_L (ctrl = "00000001") res := (op1 << 1) | tx;
tx := tx >> 31;
Here is the VHDL code:
library ieee;
use ieee.std_logic_1164.all;
entity test is
port
(
op1 : in std_logic_vector(31 downto 0); -- Input operand
ctrl : in std_logic_vector(7 downto 0); -- Control signal
clk : in std_logic; -- clock
res : out std_logic_vector(31 downto 0) -- Result
);
end;
architecture rtl of test is
type res_sel_type is (GET, SH1_L);
constant Z : std_logic_vector(31 downto 0) := (others => '0');
signal res_sel : res_sel_type;
signal load : std_logic := '0';
signal shl : std_logic := '0';
signal tx : std_logic_vector(31 downto 0) := (others => '0');
signal inp1 : std_logic_vector(31 downto 0) := (others => '0');
begin
dec_op: process (ctrl, op1)
begin
res_sel <= GET;
load <= '0';
shl <= '0';
inp1 <= ( others => '0');
case ctrl is
-- store operand
when "00000000" =>
inp1 <= op1;
load <= '1';
res_sel <= GET;
-- 1-bit left-shift with carry
when "00000001" =>
inp1 <= op1;
shl <= '1';
res_sel <= SH1_L;
when others =>
-- Leave default values
end case;
end process;
sel_out: process (res_sel, inp1, tx)
begin
case res_sel is
when SH1_L =>
res <= ( inp1(30 downto 0) & '0' ) or tx;
when others =>
res <= (others => '0');
end case;
end process;
sync: process(clk)
begin
if clk'event and clk = '1' then
if load = '1' then
tx <= op1;
elsif shl = '1' then
tx <= Z(30 downto 0) & op1(31);
end if;
end if;
end process;
end rtl;
TESTPROGRAM
GET 0 (this sets tx <= 0 )
SH1_L 0xfedcba90 exp. output: 0xfdb97520 act. output = 0xfdb97521
SH1_L 0x7654321f exp. output: 0xeca8643f act. output = 0xeca8643f
SH1_L 0x71234567 exp. output: 0xe2468ace act. output = 0xe2468ace
As you can see, the last bit is wrong for the first SH1_L operation. The first SH1_L operation produces a carry for the NEXT SH1_L operation since
the MSB is set to one of the input, however, it seems that this carry is already considered in the current SH1_L operation, which is wrong (tx should be zero).
I checked the synthesis report and there are no latches, so I am a bit clueless and almost desperate what is going wrong here. I use Xilinx ISE 12.1 for
synthesis, could there be a problem because I do not have a reset signal in my architecture, that the wrong kind of latches are instantiated?
Many thanks for further helpful comments to solve this issue,
Patrick
Unlike RTL simulation, real-life timing of inputs and clocks is not ideal. For example, the clock tree might have a longer delay than input buffers or vice versa. Did you take this into account?