Prevent sharing of adder logic - vhdl

Suppose the following VHDL component:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity adder is
port
(
iClk : in std_logic;
iDataA : in unsigned(7 downto 0);
iDataB : in unsigned(7 downto 0);
iDataC : in unsigned(7 downto 0);
oResultA : out unsigned(7 downto 0);
oResultB : out unsigned(7 downto 0)
);
end entity;
architecture behaviour of adder is
begin
process
begin
wait until rising_edge(iClk);
if iDataB /= 0 then
oResultA <= iDataA + iDataB;
else
oResultB <= iDataA + iDataC;
end if;
end process;
end behaviour;
As it can be seen it contains two additions. I expected that the synthesized logic would also contain two adders. Instead Quartus seems to think it’s a good idea to use only a single adder and mux the second input to it (see RTL below). In my opinion this does not make any sense. It saves no hardware resources because the mux requires the same number of logic elements as the adder would have required. Additionally the mux needs to wait until the if condition is evaluated, which results in worse timing.
I’ve had this happen with a much larger component and a large state machine, which lead to timing violations. How do I prevent this sort of “optimization”? I’ve set the optimization mode to “Performace (Aggressive – increases runtime and area)”, but it doesn’t seem to make a difference. The only thing which lead to the expected result was to introduce additional signals like so:
tmpA <= iDataA + iDataB;
tmpB <= iDataA + iDataC;
process
begin
wait until rising_edge(iClk);
if iDataB /= 0 then
oResultA <= tmpA;
else
oResultB <= tmpB;
end if;
end process;
Is there a better way to do this, as it makes the code really hard to read. I'm using Quartus 20.1 with a Max10 FPGA.
RTL view:

Check that an option (in Advanced Synthsizer Settings) called "Auto Resource Sharing" is off. Resource sharing enables a synthesiser to do this adder-sharing that you want not to do.
OR
Put your adders in a different layer of hierarchy (ie in a separate entity) and then set an attribute to prevent it being optimised called keep:
attribute keep: boolean;
attribute keep of my_adder0: label is true;
attribute keep of my_adder1: label is true;
where my_adder0 and my_adder1 are the labels of your adder instances.

Related

VHDL-2008 to_01 conversion

I am getting some unexpected behavior when using the to_01 conversion function in VHDL-2008. My expectation would be that vector bits that can clearly be interpreted as high or low are mapped to '1' and '0' respectively. The remaining vector bits should be converted to '0' bits.
However, with the code depicted below, I get the whole vector converted to all '0's.
Is this behavior correct? Or is this a bug in the simulator software (ALDEC Riviera-PRO)?
Is there any IEEE function that meets my expectations or do I have to write my own function to achieve that?
library ieee;
use ieee.std_logic_1164.all;
entity test_to_01 is
end entity test_to_01;
architecture rtl of test_to_01 is
signal s_test_in : std_logic_vector(8 downto 0) := "UX01ZWLH-";
signal s_test_out : std_logic_vector(8 downto 0);
begin
s_test_out <= to_01(s_test_in);
end architecture rtl;
The observed behavior is the correct behavior. A little history about this follows.
In 2008, we propagated all of the strength reduction operations to all std_logic family packages. For better or worse, the historical implementation of to_01 comes from numeric_std and was implemented exactly as it is now. The following is an older implementation I was able to find on the web:
function TO_01(S : SIGNED ; xmap : STD_LOGIC:= '0') return SIGNED is
variable RESULT: SIGNED(S'length-1 downto 0);
variable bad_element : boolean := FALSE;
alias xs : SIGNED(s'length-1 downto 0) is S;
begin
for i in RESULT'range loop
case xs(i) is
when '0' | 'L' => RESULT(i):='0';
when '1' | 'H' => RESULT(i):='1';
when others => bad_element := TRUE;
end case;
end loop;
if bad_element then
assert NO_WARNING
report "numeric_std.TO_01: Array Element not in {0,1,H,L}"
severity warning;
for i in RESULT'range loop
RESULT(i) := xmap; -- standard fixup
end loop;
end if;
return RESULT;
end TO_01;
One of the prime directives of the VHDL WG is to not break old code. In this case it looks like this objective put forward an implementation that perhaps is less desirable.
If you want something different, you can always put it forward for the next revision of the standard. It would have to have a different name. Note we are currently closing on VHDL-2018 now, so it would be the revision after that.
Note that IEEE P1076 WG is an individual based working group. This means experienced users, such as yourself, are participating. Typically the amount of work done in a standards revision is overwhelming. As a result, we always need more active participants. Particularly working on the packages. See eda-twiki.org and http://www.eda-twiki.org/cgi-bin/view.cgi/P1076/WebHome
I found a workaround:
s_test_out <= to_stdlogicvector(to_bitvector(s_test_in));

VHDL generate a constant signal

I need to generate a constant high signal pulse_out to output to an oscilloscope.
I tried letting the output signal pulse_out <='1' and this didnt work either. I believe due to my knowledge that an output port signal needs to be driven by a clock.
I also tried using combinational logic and letting a two signals that were opposite of each other make a new signal by using AND,OR and this did not work either.
I know it is a stupid question, but I am stumped.
Any sample code of showing how to output a constant high value of '1' would be great.
I agree with Josh's comment on checking your pin numbers and pin report to make sure you are driving the pin you think you are. Setting a signal to '1' should drive the pin high.
You can double check it too by driving a divided clock out and give yourself an edge to trigger a scope on.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_arith.ALL;
ENTITY test IS
PORT (i_clk : IN std_logic;
i_reset : IN std_logic;
o_scope : OUT std_logic
);
END test;
ARCHITECTURE behv OF test IS
SIGNAL scope : std_logic;
BEGIN
p1 : PROCESS (i_clk, i_reset)
BEGIN
IF i_reset = RESET_LEVEL THEN
scope <= '0';
ELSIF clk'event AND clk = '1' THEN
scope <= NOT scope;
END IF;
END PROCESS p1;
o_scope <= scope;
END behv;

VHDL Parametric case

I've some problem with my synthesis tool. I'm writing a module and I'm tryng to make it parametric and scalable. In my design I've a FSM and some counters. The counters have a parametric width ( they are function of the width of the datapath ). The problem is that I'm using that counter to drive a case statements. The synthesizer gives me back this error :
2049990 ERROR - (VHDL-1544) array type case expression must be of a locally static subtype
I've also tried to use subtype, but it doesnt work. The declaration is :
constant LENGTH_COUNTER_WORD : integer := integer(ceil(log2(real(WIDTH_DATA/WIDTH_WORD))));
subtype type_counter_word is std_logic_vector( LENGTH_COUNTER_WORD - 1 downto 0);
signal counter_word : std_logic_vector( LENGTH_COUNTER_WORD - 1 downto 0);
The case :
case type_counter_word'(counter_word) is
when (others => '1') =>
do_stuff();
when others =>
do_other_stuff();
end case;
I cannot switch to VHDL-2008. I've read I can use variable, but I'd like to find a different solution, if it exists. I cannot imagine there isn't any way to give parameters to synthesizer before the synthesis.
This is fixed in VHDL-2008. You can only work around it in earlier standards by using cascaded if statements (with the attendant priority logic). Variables don't make a difference when determining if choices are locally static.
I'm not sure how complicated your do_stuff() and do_other_stuff() operations are, but if you are just doing simple signal assignments, you could look into the and_reduce() function in the ieee.std_logic_misc library.
As an example:
output <= '1' when and_reduce(type_counter_word'(counter_word)) = '1' else '0';
Otherwise, as Kevin's answer suggests, a process block using if statements might be your best option.
About the time of Kevin's good enough answer, I had written this to demonstrate:
library ieee;
use ieee.std_logic_1164.all;
use ieee.math_real.all;
entity counterword is
generic (
WIDTH_DATA: positive := 16;
WIDTH_WORD: positive := 8
);
end entity;
architecture foo of counterword is
constant LENGTH_COUNTER_WORD : integer :=
integer(ceil(log2(real(WIDTH_DATA/WIDTH_WORD))));
subtype type_counter_word is
std_logic_vector( LENGTH_COUNTER_WORD - 1 downto 0);
signal counter_word : std_logic_vector( LENGTH_COUNTER_WORD - 1 downto 0);
procedure do_stuff is
begin
end;
procedure do_other_stuff is
begin
end;
begin
UNLABELLED:
process (counter_word)
begin
-- case type_counter_word'(counter_word) is
-- when (others => '1') =>
-- do_stuff;
-- when others =>
-- do_other_stuff;
-- end case;
if counter_word = type_counter_word'(others => '1') then
do_stuff;
else
do_other_stuff;
end if;
end process;
end architecture;
Note because type_counter_word is a subtype you can provide the subtype constraints in a qualified expression for the aggregate:
if counter_word = type_counter_word'(others => '1') then
From IEEE Std 1076-2008:
9.3.5 Qualified expressions
A qualified expression is a basic operation (see 5.1) that is used to explicitly state the type, and possibly the subtype, of an operand that is an expression or an aggregate.
This example analyzes, elaborates and simulates while doing nothing in particular. It'll call the sequential procedure statement do_other_stuff, which does nothing.
(For do_stuff and do_other stuff, empty interface lists aren't allowed).

VHDL Program counter using signals and previously made components?

I am currently in the middle of a project where I am attempting to design a single cycle cpu. I am doing this without any pipe-lining, since that would greatly add to the complexity of the design. I am simply taking baby steps as I learn this. I find myself stuck at this portion where I am simply attempting to code a Program Counter(PC) using previously made components.
The model of my design looks like this picture here. Sorry, no idea why it came out dark, but if you click on it it shows correctly. The PC and theMUX are both 32 bit components, so I assume the adder is as well.
Here is the code I have been given, my implementation begins at the begin statement on line 41.
Pay no attention to it for now, its just a bunch of random gibberish I was attempting.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
---------------------------------------------------
entity pc_update is
port( clk: in std_logic; -- clock
incH_ldL: in std_logic; -- increment PC = PC + 4 when high,
-- load PCInput when low
PCInput: in std_logic_vector(31 downto 0); -- external input for PC
InstrAddr: out std_logic_vector(31 downto 0) ); -- instruction address
end entity pc_update;
----------------------------------------------------
architecture pc_update_arch of pc_update is
component register32 is
port( clr: in std_logic; -- async. clear
clk: in std_logic; -- clock
ld: in std_logic; -- load
D: in std_logic_vector(31 downto 0); -- data input
Q: out std_logic_vector(31 downto 0) ); -- data output
end component register32;
component mux2to1_32 is
port( sel: in std_logic; -- selection bit input
X0: in std_logic_vector(31 downto 0); -- first input
X1: in std_logic_vector(31 downto 0); -- second input
Y: out std_logic_vector(31 downto 0)); -- output
end component mux2to1_32;
signal PC_current: std_logic_vector(31 downto 0); -- the current state of PC reg
signal PC_add_4: std_logic_vector(31 downto 0); -- output from the adder
signal PC_next: std_logic_vector(31 downto 0); -- output from the MUX
begin
PC: register32 Port Map(
clk, Q, clr, D);
MUX: mux2to1_32 Port Map(
X0,sel,X1,Y);
process (incH_ldL)
begin
wait until (clk = '1');
if incH_1dL = '0' then
InstrAddr <= X0;
else InstrAddr <= X1;
end if;
end process;
end architecture pc_update_arch;
I am fairly new to this so I have only a faint idea of how signals work, and no idea how I am supposed to implement the components into the design. I am also confused that I wasnt asked to build the adder ahead of time. Is it now necessary to use it as a component im guessing?
Anyhow, I have attempted different things that stumbled upon searching, such as the port mapping you see. But I always get some sort of error, currently the error im receiving is that objects Q, clr, and D are used but not declared. How do I declare them?
If I get rid of those statements, the error simply repeats for objects X0, X1, and Y.
Any help in the right direction would be greatly appreciated. Thanks guys!
Also, just in case you need them,
The register
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
---------------------------------------------------
entity register32 is port(
clr: in std_logic; -- async. clear
clk: in std_logic; -- clock
ld: in std_logic; -- load
D: in std_logic_vector(31 downto 0); -- data input
Q: out std_logic_vector(31 downto 0) ); -- data output
end entity register32;
----------------------------------------------------
architecture register32_arch of register32 is
begin
process(clk, clr)
begin
if clr = '1' then
q <= x"00000000";
elsif rising_edge(clk) then
if ld = '1' then
q <= d;
end if;
end if;
end process;
END register32_arch;
and the MUX
library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
---------------------------------------------------
entity mux2to1_32 is
port( sel: in std_logic; -- selection bit input
X0: in std_logic_vector(31 downto 0); -- first input
X1: in std_logic_vector(31 downto 0); -- second input
Y: out std_logic_vector(31 downto 0)); -- output
end entity mux2to1_32;
----------------------------------------------------
architecture mux2to1_32_arch of mux2to1_32 is
begin
Y <= X1 when (SEL = '1') else X0;
end architecture mux2to1_32_arch;
EDIT
Ok, NO idea if I did this correctly, but I rewrote the portmaps. I was having errors of port names (sel, clk, X0, X1..etc) being "used but not initialized. So that is why clr, clk and ld have initial values. Once again, no idea if that is correct, but it made the errors go away. I also realized I never added the register32 and mux2to1_32 VHDL files to my project, and after doing so got rid of the other errors I was having.
So as stands, the code compiles, I have included in the project a VWF simulation file for testing, but I KNOW the results are gonna be incorrect.
I dont know everything that is wrong yet, but I know I need to do something with PC_add_4. THis value needs to basically be (PC_current + 4), but Im not sure how to do this.
Here is the updated portion of code(everything else is the same)
PC: register32 Port Map(
clr => '0',
clk => '0',
ld => '1',
Q => PC_current,
D => PC_next
);
MUX: mux2to1_32 Port Map(
sel => incH_ldL,
X0 => PCInput ,
X1 => PC_add_4,
Y => PC_next
);
process (incH_ldL)
begin
if (rising_edge(clk)) then
if incH_ldL = '0' then
InstrAddr <= PC_current;
else InstrAddr <= PC_add_4;
end if;
end if;
end process;
And, in case they help, my list of errors..im guessing the pin related errors are because I dont have any hardware assignments made yet.
Warning (10541): VHDL Signal Declaration warning at pc_update.vhd(38): used implicit default value for signal "PC_add_4" because signal was never assigned a value or an explicit default value. Use of implicit default value may introduce unintended design optimizations.
Warning (10492): VHDL Process Statement warning at pc_update.vhd(61): signal "clk" is read inside the Process Statement but isn't in the Process Statement's sensitivity list
Warning: Output pins are stuck at VCC or GND
Warning: Design contains 34 input pin(s) that do not drive logic
Warning: Found 32 output pins without output pin load capacitance assignment
Warning: The Reserve All Unused Pins setting has not been specified, and will default to 'As output driving ground'.
Warning: Can't generate programming files because you are currently using the Quartus II software in Evaluation Mode
Warning: No paths found for timing analysis
Critical Warning: No exact pin location assignment(s) for 66 pins of 66 total pins
SECOND EDIT
So yeah I fixed up my code by adding
PC_add_4 <= (PC_current + 4 );
after the port mappings, and adding "clk" to the process sensitivity list.
However my waveforms in my simulation are still wrong I believe, as shown here.
It appears to be treating incH_lDL as a clear signal, rather than simply passing PCInput to InstrAddr. This is most likely due to my setting of it to a default '0' in the port map. I did this earlier because it was giving me "used but not declared" errors. Ill try messing with it and post my findings.
Third EDIT
I have edited my code as such:
process (incH_ldL, clk)
begin
if rising_edge(clk) then
if (incH_ldL = '0') then
InstrAddr <= PCInput ;
else InstrAddr <= PC_add_4;
end if;
end if;
end process;
My simulation now shows that when incH_lDL = 0, PCInput is loaded into InstrAddr, however, when incH_lDL = 1, it simply loads the value '4', and doesnt increment at the start of every clock cycle like its supposed to...I need to make use of PC_current, but I am not sure how....sicne you cant assign one signal to another like "PC_current <= PCInput". I will try some more things,in the mean time, any pointers would be greatly appreciated.
FOURTH EDIT
THanks to anyone still reading this, and bearing through all the reading.
I have attempted to use PC_next and PC_current in my implementation, but have run into "multiple constant drivers for net "PC_next" errors.
MY process code:
process (incH_ldL, clk, PC_next, PC_current)
begin
if rising_edge(clk) then
if (incH_ldL = '0') then
PC_next <= PCInput;
else PC_next <= PC_add_4;
end if;
end if;
InstrAddr <= PC_current;
end process;
I am aware that this error comes when these assignments are made within loops? I am truly at a loss here at what to try next.
Your port maps in the first code need to be ported to signals. You are placing the port names of the components in the port map, which is incorrect. What you would like to do is create signals that can connect those components, and place them in the port map fields instead (to match the connections in your image).

Vhdl ERROR that I don't understand

I have a problem with my vhdl code . In active-hdl it works perfectly , but when i tried to implement it on the FPGA board using ise design xilinx i have a problem with one component . The error i found is:
ERROR:Xst:827 - "E:/proiect_final/dispozitiv_impartitor/src/generator_square_wave.vhd" line 16: Signal numar_intermediar<0> cannot be synthesized, bad synchronous description. The description style you are using to describe a synchronous element (register, memory, etc.) is not supported in the current software release.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity generator_square_wave is
port(clock,reset :in bit;
controler:std_logic_vector(2 downto 0);
numar:out std_logic_vector(7 downto 0);
data_clock:out bit);
end generator_square_wave ;
architecture descriere of generator_square_wave is
signal reset1:std_logic;
begin
process (clock,reset) -- here it shows me the error
variable numar_intermediar:bit_vector(3 downto 0 ):="0000";
variable numar_intermediar2:std_logic_vector(3 downto 0);
variable bitul:bit;
begin
reset1<=to_stdulogic(reset);
if rising_edge(reset1) then
numar_intermediar:="0001";
numar_intermediar2:=To_StdLogicVector(numar_intermediar);
numar(0)<=numar_intermediar2(0);
numar(1)<=numar_intermediar2(1);
numar(2)<=numar_intermediar2(2);
numar(3)<=numar_intermediar2(3);
numar(4)<='0';
numar(5)<='0';
numar(6)<='0';
numar(7)<='0';
else if( clock'event and clock ='1' and controler="001")then
bitul:=numar_intermediar(0);
numar_intermediar:=numar_intermediar srl 1;
numar_intermediar(3):=bitul;
numar_intermediar2:=To_StdLogicVector(numar_intermediar);
numar(0)<=numar_intermediar2(0);
numar(1)<=numar_intermediar2(1);
numar(2)<=numar_intermediar2(2);
numar(3)<=numar_intermediar2(3);
numar(4)<='0';
numar(5)<='0';
numar(6)<='0';
numar(7)<='0';
if(reset/='1' and controler/="001")then
numar<="00000000";
end if;
end if;
end if;
data_clock<=clock;
end process;
end descriere;
You have a few problems. First, you shouldn't be treating reset as a clock (i.e. using rising_edge()). If it's asynchronous, you should just write:
if reset1 = '1' then
...
The following line also has a problem (not sure if this is strictly illegal, but it's not recommended):
if( clock'event and clock ='1' and controler="001")then
This should be:
if clock'event and clock = '1' then
if controler = "001" then
(with additional end if to match.)
That should at least allow it to synthesize.
You may also want to make the statement reset1<=to_stdulogic(reset) concurrent instead of including it in the process, and there are a couple other possible changes you could make, but they're not as critical (unless I've missed something).

Resources