I'm using QuestaSim, which is supposedly the same thing as ModelSim but 64-bit. I'm trying to run a test bench for an assignment due in class tomorrow. The assignment is done and all I need is the test bench, but QuestaSim is being annoying as usual.
For some reason, the test bench file just WILL NOT compile. I cannot for the life of me figure out why, though I recall it working on ModelSim the last time I tried this.
Here's the code for the test bench.
library ieee;
use ieee.std_logic_1164.all;
entity test_bench is
end entity test_bench;
architecture lab1atest of test_bench is
signal X, Y, M: std_logic_vector (7 downto 0);
signal s: std_logic;
begin
dut : entity lab1a
port map ( X=>X, Y=>Y, s=>s, M=>M);
stimulus : process is
begin
X <= "10101010"; Y <= "01010101"; s <= '0'; wait for 20 ns;
s <= '1'; wait for 20 ns;
X <= "11110000"; wait for 20 ns;
s <= '0'; wait for 20 ns;
Y <= "00001111";
wait;
end process stimulus;
end architecture lab1atest;
The code for lab1a.vhd I can't post because it's to be submitted for an assignment and I don't want to get nailed for plagiarizing myself, but know that the entity "lab1a" most certainly exists in that file and I am making sure to compile that file first (though I have tried the other way around, just in case).
In addition to the standard selecting of the files and hitting compile, I've also tried the following:
vlib work;
vmap work work;
vcom lab1a.vhd;
vcom lab1atest.vhdl;
vsim work.lab1atest;
Both produce the same error.
If any of you have any idea why I am getting the error highlighted in the title, please let me know. I feel like this is an incredibly simple fix and I am currently cursing the designers of said product for making it so unintuitive.
I genned a dummy entity/architecture for lab1a that does nothing but has proper connectivity.
The immediate issue why it won't 'analyze' is that the entity lab1a isn't made visible to test_bench.
dut : entity lab1a
port map ( X=>X, Y=>Y, s=>s, M=>M);
should be
dut: entity work.lab1a
port map ( ...
or you should make the contents of your working directory visible in your context clause by adding a use clause:
use work.all; -- or some variant form
After implementing the selected name (work.lab1a, an expanded name is a form of selected name, see IEEE Std 1076-2008, 8.3 Selected names, paragraph 7) the code analyzed with a previously analyzed lab1a:
library ieee;
use ieee.std_logic_1164.all;
entity lab1a is
port (
X: in std_logic_vector (7 downto 0);
Y: in std_logic_vector (7 downto 0);
s: in std_logic;
M: out std_logic_vector (7 downto 0)
);
end entity;
architecture foo of lab1a is
begin
end architecture;
And why the dummy lab1a works is because an architecture isn't required to contain concurrent statements:
architecture_body ::=
architecture identifier of entity_name is
architecture_declarative_part
begin
architecture_statement_part
end [ architecture ] [ architecture_simple_name ] ;
architecture_statement_part ::=
{ concurrent_statement }
IEEE Std 1076-2008. 1.3.2 Synaptic description, f):
Braces enclose a repeated item or items on the right-hand side of a
production. The items may appear zero or more times; the repetitions
occur from left to right as with an equivalent left-recursive rule.
Extended Backus-Naur Form text found in the numbered clauses of the standard is normative.
And there's another solution, the use of a component declaration and component instantiation instead of direct entity instantiation.
This would count on default binding indication to find a previously analyzed lab1a during elaboration. (7.3.3 Default binding indication).
Related
I am using NUMERIC_STD library. The incoming PORT signal is RAM_BYTE_EN to be converted as constant integer number RAM_WIDTH.
'''
RAM_BYTE_EN : IN std_logic_vector(3 downto 0); -- Value "0100" passed as RAM_BYTE_EN
constant RAM_WIDTH : natural := to_integer(unsigned(RAM_BYTE_EN)); --convert RAM_BYTE_EN
'''
In simulation, the value RAM_WIDTH is ZERO and not 4.
Don't understand why the conversion is not working. What am I missing?
In simulation, the value RAM_WIDTH is ZERO and not 4.
Setting aside for the moment the anticipated synthesis of an unseen design unit and/or hierarchy and focus on simulation:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rambyteenab is
port (
RAM_BYTE_EN : IN std_logic_vector(3 downto 0) -- Value "0100" passed as RAM_BYTE_EN -- struck semicolon
);
end entity;
architecture foo of rambyteenab is
constant RAM_WIDTH : natural := to_integer(unsigned(RAM_BYTE_EN)); -- convert RAM_BYTE_EN
begin
process
begin
report "RAM_WIDTH = " & integer'image(RAM_WIDTH);
wait;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity higher_in_hierarchy is
end entity;
architecture working of higher_in_hierarchy is
signal RAM_BYTE_ENAB: std_logic_vector(3 downto 0) := "0100";
begin -- RAM_BYTE_ENAB is "0100" when inst is elaborated
inst:
entity work.rambyteenab
port map (RAM_BYTE_EN => RAM_BYTE_ENAB);
end architecture;
architecture failing of higher_in_hierarchy is
signal RAM_BYTE_ENAB: std_logic_vector(3 downto 0);
begin -- STATEMENTS ELBORATED in order
inst:
entity work.rambyteenab
port map (RAM_BYTE_EN => RAM_BYTE_ENAB);
concurrent_signal_assignment:
RAM_BYTE_ENAB <= "0100";
end architecture;
By analyzing the above four design units and either using a configuration specification or configuration declaration or elaboration time command line options to specify which architecture of higher_in_hierarchy to use with a declaration of signal RAM_BYTE_ENAB used as an actual in associating the port RAM_BYTE_EN of entity rambyteenab we can demonstrate it's possible to rely on the value of a port signal of mode in at elaboration time.
It depends on the port signal having been initialized to a useful value and elaboration order guaranteeing that value prior to it's evaluation.
All four design units are found in order in the same design file which is analyzed into a reference library (work):
ghdl -a rambyteenab.vhdl
The target architecture of higher_in_hierarchy is elaborated separately using both architectures:
ghdl -e higher_in_hierarchy failing
ghdl -e higher_in_hierarchy working
Note that elaborating higher_in_hierarchy without specifying the architecture would result in using the architecture working, which is the last analyzed architecture, working being used by default.
These produce elaborated design hierarchies:
%: ls -aF higher*
/Users/user16145658/Desktop
-rwx--x--x 1 user16145658 staff 1270312 Feb 2 05:32 higher_in_hierarchy-failing*
-rwx--x--x 1 user16145658 staff 1269544 Feb 2 05:33 higher_in_hierarchy-working*
which can be used to demonstrate the ability to use elaboration order and initialization value to pass the value of a signal to be used in the elaboration of a constant, at elaboration time:
%: higher_in_hierarchy-working
rambyteenab.vhdl:16:9:#0ms:(report note): RAM_WIDTH = 4
%: higher_in_hierarchy-failing
../../src/ieee/v93/numeric_std-body.vhdl:2098:7:#0ms:(assertion warning): NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0
rambyteenab.vhdl:16:9:#0ms:(report note): RAM_WIDTH = 0
%:
The failure is by virtue of RAM_BYTE_ENAB having a a default initialization of all 'U's which generates the numeric_std warning assertion in simulation. The OP should have encountered a similar warning during simulation as the only means of producing a zero through elaboration.
So, what about synthesis?
Historically IEEE Std 1076.6-2004 VHDL Register Transfer Level (RTL) Synthesis (withdrawn due to lack of vendor participation and age) for RAM_BYTE_ENAB told us:
8.4.3.1 Object declarations
b) Signal declarations
...
The initial value expression shall be ignored unless the declaration is in a package, where the declaration shall have an initial value expression.
which didn't allow for depending on the initial value, a practice supported generally in memory based FPGAs today. Some number of tool implementations for target device architectures not capable of passing initial values through lack of passing memory or ability to otherwise pull up or pull down nets still do not make use of initial values.
The reliance on initial values isn't possible in a portable fashion.
Constants should be known at synthesis time and cannot be derived from signals. For the RAM to be instantiated, its width needs to be known. So you should set it to a constant number e.g.
constant RAM_WIDTH : natural := 32;
That's my code:
-- Insert library and use clauses
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY Questao1 IS
-- Begin port declaration
PORT (
-- Declare data inputs "dataa" and "datab"
dataa, datab : in STD_LOGIC_VECTOR (15 DOWNTO 0);
-- Declare data output "sum"
sum : out STD_LOGIC_VECTOR (15 DOWNTO 0)
);
-- End entity
END ENTITY Questao1;
-- Begin architecture
ARCHITECTURE logic OF Questao1 IS
BEGIN
sum <= x"000A" WHEN dataa = x"0001" ELSE x"000B" WHEN datab = x"0001" ELSE x"000C";
dataa <= x"0001", x"0000" AFTER 20 NS, x"000A" AFTER 30 NS;
datab <= x"0000", x"0001" AFTER 20 NS, x"0005" AFTER 30 NS;
-- End architecture
END ARCHITECTURE logic;
That's my error:
Error (10568): VHDL error at Questao1.vhd(44): can't write to interface object "dataa" of mode IN
Someone can help? I'm beginning in VHDL
It seems you were a given a task to write a testbench to test your code.
Generally speaking a vhdl code for a design represents how the design should behave. If you wish to test it if it really does, what it is supposed to do, you need to 'wrap' it in a bigger device, to be able to send signals to your 'device under test'.
This is often done with the use of testbenches - a vhdl code that uses your entity as a component and sends signals to it.
Next thing to note is that any time specific commands (like 'AFTER' in your case) are not synthesizable. However you can simulate behaviour of your design using software tools, like modelsim.
Another thing is that you cannot assign values to input. Input ports receive data from 'outside world', you cannot alter the data your entity receives from within the entity itself.
I am new(ish) to VHDL. I am trying to understand how to use different component .vhd files to build a complete structure. I am working with a Digilent PmodA7, and want to have two LEDs blink alternately.
What I have tried is Inverter.vhd and LedBlink.vhd
Inverter.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Inverter is
Port (
Inv_in : in std_logic;
Inv_out : out std_logic
);
end Inverter;
architecture Behavioral of Inverter is
begin
Inv_out <= not Inv_in;
end Behavioral;
Ledblink-1.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
entity LedBlink is
Port (
clk: in std_logic;
rst: in std_logic;
led_0 : out std_logic;
led_1 : out std_logic
);
end LedBlink;
architecture Behavioral of LedBlink
-- Inverter.vhd
component Inverter is
port (
Inv_in : in std_logic;
Inv_out : out std_logic
);
end component;
constant CLK_FREQ : integer := 12500000;
constant BLINK_FREQ : integer := 1;
constant CNT_MAX : integer := CLK_FREQ/BLINK_FREQ/2 - 1;
signal cnt : unsigned(24 downto 0);
signal blink_0 : std_logic := '1';
signal blink_1 : std_logic := '1';
begin
process(clk)
begin
if (rst = '1') then
blink_0 <= '0';
blink_1 <= '0';
elsif (clk='1' and clk'event ) then
if cnt = CNT_MAX then
cnt <= (others => '0');
-- blink_1 <= blink_0;
A1: Inverter
Port map ( Inv_in => blink_0, Inv_out => blink_1);
blink_0 <= not blink_0;
else
cnt <= cnt + 1;
end if;
end if;
end process;
led_0 <= blink_0;
led_1 <= blink_1;
end Behavioral;
To understand how to combine files, I want to replace the line
blink_1 <= blink_0;
with a inverter component, ie 7404, but can’t figure out how to do this. The example I am following does not use libraries, so I am most interested in that method, although how to a library to accomplish this would be helpful.
What I have is:
You haven't provided a Minimal, Complete, and Verifiable example with an error. Questions asking for programming help on stackoverflow are practical, not theoretical. This implies a specific problem here.
Analysis (compiling) won't complete o with the missing is in the architecture bodyr or component instantiation in the unlabelled process.
You can't instantiate a component (a concurrent statement) in a process (which can only contain sequential statements). Move the component instance outside the process.
The flip flop output blink_0 is inverter's input. It's output blink_1 is then assigned to blink_0 in the process instead of not blink_0.
blink_1 is only assigned in the elaborated process from the concurrent assignment statement in the architecture of inverter. Each process in a design hierarchy has a driver. The value of multiple drivers are resolved during simulation. The equivalent post synthesis is having two devices driving the same signal and would generate a synthesis error.
Analyze Inverter.vhd before elaborating LedBlink.
cnt must be reset for simulation for the increment, adding 1 to all 'U's will result in all 'U's. You don't use package std_logic_unsigned.
library ieee;
use ieee.std_logic_1164.all;
-- use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity ledblink is
port (
clk: in std_logic;
rst: in std_logic;
led_0: out std_logic;
led_1: out std_logic
);
end entity ledblink;
architecture behavioral of ledblink is -- ADDED is
component inverter is
port (
inv_in: in std_logic;
inv_out: out std_logic
);
end component;
constant clk_freq: integer := 12500000;
constant blink_freq: integer := 1;
constant cnt_max: integer := clk_freq/blink_freq/2 - 1;
signal cnt: unsigned(24 downto 0);
signal blink_0: std_logic := '1';
signal blink_1: std_logic := '1';
begin
process (clk) -- contains counter cnt and flip flop blink_0
begin
if rst = '1' then
blink_0 <= '0';
-- blink_1 <= '0'; -- ONLY one driver for blink_1, the component
cnt <= (others => '0'); -- ADD cnt to reset
elsif clk = '1' and clk'event then -- OR rising_edge(clk)
if cnt = cnt_max then
cnt <= (others => '0');
-- blink_1 <= blink_0;
-- a1: inverter MOVED to architecture body
-- port map ( inv_in => blink_0, inv_out => blink_1);
-- blink_0 <= not blink_0; CHANGED
blink_0 <= blink_1;
else
cnt <= cnt + 1;
end if;
end if;
end process;
a1:
inverter -- MOVED to architecture body a place for concurrent statements
port map ( inv_in => blink_0, inv_out => blink_1);
led_0 <= blink_0;
led_1 <= blink_1;
end architecture behavioral;
After which your design analyzes and with a testbench providing clock and reset, elaborates and simulates:
Note cnt only requires a length of 23 (22 downto 0), cnt(24) and cnt(23) are always '0' with a 12.5 MHz clock (12500000).
The question notes "The example I am following does not use libraries, so I am most interested in that method, although how to a library to accomplish this would be helpful."
The first clause isn't exactly accurate. See IEEE Std 1076-2008 13.2 Design libraries:
A design library is an implementation-dependent storage facility for previously analyzed design units. A given implementation is required to support any number of design libraries.
...
There are two classes of design libraries: working libraries and resource libraries. A working library is the library into which the library unit resulting from the analysis of a design unit is placed. A resource library is a library containing library units that are referenced within the design unit being analyzed. Only one library is the working library during the analysis of any given design unit; in contrast, any number of libraries (including the working library itself) may be resource libraries during such an analysis.
Every design unit except a context declaration and package STANDARD is assumed to contain the following implicit context items as part of its context clause:
library STD, WORK; use STD.STANDARD.all;
Library logical name STD denotes the design library in which packages STANDARD, TEXTIO, and ENV reside (see Clause 16). (The use clause makes all declarations within package STANDARD directly visible within the corresponding design unit; see 12.4.) Library logical name WORK denotes the current working library during a given analysis. Library logical name IEEE denotes the design library in which the mathematical, multivalue logic and synthesis packages, and the synthesis context declarations reside (see Clause 16).
A design specification is analyzed into the working library which can be referenced by work and can be implementation dependent method redirected.
There are rules for determining the default binding indication (in lieu of a binding indication in a configuration specification as a block declarative item for a block (including an architecture body) containing a component instantiation or in a configuration declaration (not widely used by synthesis tools, if at all). See 11.7 Component instantiation and 3.4.3 Component configuration.
Without an explicit binding indication as here VHDL relies on a default binding indication (7.3.3 Default binding indication):
In certain circumstances, a default binding indication will apply in the absence of an explicit binding indication. The default binding indication consists of a default entity aspect, together with a default generic map aspect and a default port map aspect, as appropriate.
If no visible entity declaration has the same simple name as that of the instantiated component, then the default entity aspect is open. A visible entity declaration is the first entity declaration, if any, in the following list:
a) An entity declaration that has the same simple name as that of the instantiated component and that is directly visible (see 12.3),
b) An entity declaration that has the same simple name as that of the instantiated component and that would be directly visible in the absence of a directly visible (see 12.3) component declaration with the same simple name as that of the entity declaration, or
c) An entity declaration denoted by L.C, where L is the target library and C is the simple name of the instantiated component. The target library is the library logical name of the library containing the design unit in which the component C is declared.
These visibility checks are made at the point of the absent explicit binding indication that causes the default binding indication to apply.
In this case because inverter was analyzed into the same resource library (an unchanging work) following rule b). You can note that these rules are set up to be as painless as possible. There can be only one primary unit (here an entity) with the same name in a library.
Anyway the point is that there are libraries involved in the original post's code. Here without a configuration specification inverter is expected to be found in library work, regardless of what resource library it references in an implementation defined manor.
It's out of the scope of the vhdl tag and the original post does not identify a particular tool implementation, and VHDL tools are varied in methods for associating working and resource libraries with library logical names.
For a resource library made visible by a library clause a use clause of the form 'use library_logical_name.all;' can make all named entities in a resource library directly visible (See 12.4 Use Clauses, 12.3 Visibility, 12.5 The context of overload resolution). Otherwise a selected name for an instantiated entity can be used (8.3 Selected names).
Using the first snippet of code, I have been getting this error that a bunch of my signals drove no pins. I am pretty certain that this is because in the first snippet of code, the first if statement is never reached. Why would this be so? In the second snippet I modified the code, and all of my problems have been fixed. I made the change as an intuitive impulse, I have no idea why that fixed everything. Could someone explain maybe how the Synthesizer generates the circuit?
First Snippet:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity DataReg is
generic(N: integer := 8);
port(DIN: in std_logic_vector(N - 1 downto 0);
DOUT: out std_logic_vector(N - 1 downto 0);
CLK: in std_logic;
ENABLE: in std_logic;
RESET: in std_logic);
end DataReg;
architecture Behavioral of DataReg is
begin
process(CLK, ENABLE)
begin
if rising_edge(CLK) and ENABLE = '1' then
DOUT <= DIN;
end if;
if rising_edge(CLK) and RESET = '1' then
DOUT <= (others => '0');
end if;
end process;
end Behavioral;
Second snippet: (Fixed code)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity DataReg is
generic(N: integer := 8);
port(DIN: in std_logic_vector(N - 1 downto 0);
DOUT: out std_logic_vector(N - 1 downto 0);
CLK: in std_logic;
ENABLE: in std_logic
RESET: in std_logic);
end DataReg;
architecture Behavioral of DataReg is
begin
process(CLK, ENABLE)
begin
if rising_edge(CLK) then
if ENABLE = '1' then
DOUT <= DIN;
elsif RESET = '1' then
DOUT <= (others => '0');
end if;
end if;
end process;
end Behavioral;
Because HDL code must be able to represent existing hardware. Therefore when you write RTL (Register Transfer Level) code you have to stick to certain structures. Even the second code you wrote is not correct.
I can't explain all the rules but basically, to use an edge (rising or falling) you can have only one signal. Not OR-es or And-es etc.:
if rising_edge(CLK) then
In such a clocked section your process can have one or two more sensitivity signals. Often there is an asynchronous reset in some exceptional cases there is also an asynchronous set. For those to work you have to place the condition before the clock. Therefore your code is wrong. Your ENABLE and RESET are only looked at when there is a clock edge. Thus putting ENABLE in the sensitivity list is superfluous. You might just as well leave it out.
Furthermore the ENABLE if is before the RESET. Thus if the ENABLE is high your RESET will be ignored. Probably not what you want!
The code for a clocked section is sooo terribly standard that I often copy a template I have laying around. (I always use asynchronous active low reset)
process(clk, reset_n)
begin
if (reset_n='0') then
elsif rising_edge(clk) then
end if; -- reset/clocked
end process;
First of all, the two pieces of code that you present are not even equivalent in the simulator because when ENABLE and RESET are both 1 on a clock edge, the first snippet results in DOUT being 00000000 whereas in the second one it evaluates to DIN.
It is my impression that the sensitivity lists (the part in parentheses after process) are ignored during synthesis by Xilinx Vivado. I consider them a relic from times when simulation tools could not afford deducing which variables should be monitored to determine when variables should be updated. I don't know what other synthesis tools do with them.
Anyway, you specified ENABLE in your sensitivity list, which means that you want to evaluate the process statements if ENABLE changes value. All if-statements evaluate to false unless a rising clock edges is taking place. Therefore, CLK alone in the sensitivity list is sufficient for simulation.
All that being said, you should restrict your code to formats that are explicitly recommended by the synthesis tool vendor. Synthesis tools can only implement a subset of everything that you can write in VHDL. For Vivado, you can find suggested code structure in the synthesis manual (This one is for Vivado 2017.3). On page 71, you will see that they recommend flip-flops of the form:
process(clk) is
begin
if rising_edge(clk) then
if clr = '1' then
dout <= "00000000";
elsif ce = '1' then
dout <= d_in;
end if;
end if;
end process;
You can rename the variables as needed of course. On page 69, you will also see that Xilinx recommends using synchronous implementations (putting everything inside the rising_edge if-statement) over asynchronous implementations. There is much more in the manual, for example about how to write shift registers or RAMs, which you should become familiar with if you want to write code to be synthesized with Vivado. Other vendors have similar documentation with recommended code.
I have the following code:
entity wave_select is
port( address:in std_logic_vector(6 downto 0);
ws1: in std_logic;
ws0: in std_logic;
wave_out: out std_logic_vector(6 downto 0));
end wave_select;
architecture choose_arch of wave_select is
signal internal_sine:std_logic_vector(6 downto 0);
signal internal_tri:std_logic_vector(6 downto 0);
signal internal_sqr:std_logic_vector(6 downto 0);
begin
U0: entity sine_tbl port map(addr=>address, sine_val=>internal_sine);
U1: entity triangle_tbl port map(addr=>address, tri_val=>internal_tri);
U2: entity square_tbl port map(addr=>address, square_val=>internal_sqr);
process (std_logic_vector'(ws1, ws0))
begin
case ws_combo is
when "01" => wave_out<=internal_sine;
when "10" => wave_out<=internal_tri;
when "11" => wave_out<=internal_sqr;
when others =>wave_out<=(others => '-');
end case;
end process;
end choose_arch;`
Whenever I try to compile this, I get the following errors:
Identifier/keyword expected (for the process line)
Keyword end expected (for the when "10" line)
Design unit declaration expected (for the same line as keyword error)
FIXED THE QUESTION
As it stands right now, this has a number of problems, mostly with fairly basic syntax.
Although it seems likely you mean the combination of ws0 and ws1 to be treated as ws_combo, you haven't done anything to tell the synthesizer that, so it treats ws_combo as simply undefined.
At least as far as I know, you can't combine signals in the process sensitivity list like you've done. The sensitivity list is to tell what external signals this process responds to, not much else.
You don't have a definition of wave_out (unless it's also in your entity declaration).
You don't have definitions of internal_sine, internal_tri, or internal_sqr. Hard to guess what type they should be without knowing the type of wave_out.
As an interim idea of how this might turn out, I've fixed some of the syntax errors, added an entity declaration that declares ws0, ws1 and wave_out, then sets wave_out to values suitable to the type I've given it (in this case, just took binary input and produced Grey code output).
entity controller1 is
port (
ws1 : in std_logic;
ws0 : in std_logic;
wave_out : out std_logic_vector(1 downto 0)
);
end;
architecture whatever of controller1 is
begin
impl: process(ws0, ws1)
begin
case std_logic_vector'(ws1,ws0) is
when "01" => wave_out<="01";
when "10" => wave_out<="11";
when "11" => wave_out<="10";
when others =>wave_out<=(others => '-');
end case;
end process;
end whatever;
Of course, this also needs the typical library and using to get declarations for std_logic and std_logic_vector, but with those added the synthesizer seems to accept it. Of course, some other synthesizer (I'm checked it with Synplify) might find a problem I missed, but I think that probably covers at least most of the obvious problems.
What are you attempting to achieve with the std_logic_vector' in this line?
process (std_logic_vector'(ws1, ws0))
If you just change that for the more conventional
process (ws1, ws0)
I imagine it will help.
But I assume ws_combo is a signal like
ws_combo = ws1&ws0;
so
process (ws_combo)
would be better still.