VHDL: with-select for multiple values - select

I have the following code (it encodes a number of a pressed button):
with buttons select
tmp <= "000" when x"1",
"001" when x"2",
"010" when x"4",
"011" when x"8",
"100" when others;
code <= input(1 downto 0);
error <= input(2);
I am trying to rewrite it without using tmp signal. Is it possible? The following doesn't work:
with buttons select
error & code <= "000" when x"1",
"001" when x"2",
"010" when x"4",
"011" when x"8",
"100" when others;

Instead of with select, you could use case:
my_process_name : process(buttons)
begin
case buttons is
when x"1" =>
error <= '0';
code <= "00";
when x"2" =>
error <= '0';
code <= "01";
when x"4" =>
error <= '0';
code <= "10";
when x"8" =>
error <= '0';
code <= "11";
when others =>
error <= '1';
code <= "00";
end case;
end process;

Or you could just write this as 2 separate with/when statements:
with buttons select
error <= '0' when x"1",
'0' when x"2",
'0' when x"4",
'0' when x"8",
'1' when others;
with buttons select
code <= "00" when x"1",
"01" when x"2",
"10" when x"4",
"11" when x"8",
"00" when others;
or alternatively:
error <= '0' when (buttons = X"1" or buttons = X"2" buttons = X"4" buttons = X"8") else '1';
code <= "00" when buttons = X"1" else "01" when buttons = X"2" else "10" when buttons = X"4" else "11" when buttons = X"8" else "00";
VHDL is a compiled language - or synthesised. Any format is OK as long as the synthesis tool creates the relevant logic construct. The rest is symantics to allow code to be understood and maintained.

Related

Is there a way to simplify the case logic for an enum in verilog?

I'm looking to simplify an expression for decoding the opcode for a risc v microcontroller:
always # * begin
case (opcode)
LOAD | LOAD_FP | MISC_MEM | OP_IMM OP_IMM_32 : begin // I_TYPE
imm[0] <= inst[20];
imm[4:1] <= inst[24:21];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
STORE | STORE_FP | AMO : begin // S_TYPE
imm[0] <= inst[7];
imm[4:1] <= inst[11:8];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
BRANCH, JALR : begin // B_TYPE
imm[0] <= 0;
imm[4:1] <= inst[11:8];
imm[10:5] <= inst[30:25];
imm[11] <= inst[7];
imm[31:12] <= inst[31];
end
AUIPC, LUI, OP_32 : begin // U_TYPE
imm[11:0] <= 0;
imm[19:12] <= inst[19:12];
imm[30:20] <= inst[30:25];
imm[31] <= inst[31];
end
JAL, SYSTEM : begin // J_TYPE
imm[0] <= 0;
imm[4:1] <= inst[24:21];
imm[10:5] <= inst[30:25];
imm[11] <= inst[20];
imm[19:12] <= inst[19:12];
imm[31:20] <= inst[30];
end
default :
imm <= 0;
endcase
end
to somewthing like this:
always # * begin
case (opcode)
I_TYPE : begin
imm[0] <= inst[20];
imm[4:1] <= inst[24:21];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
S_TYPE : begin
imm[0] <= inst[7];
imm[4:1] <= inst[11:8];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
// ...continued
default :
imm <= 0;
endcase
end
Is this possible, can I add methods to an enum/class like in c++, is this worth doing, if so how?
this is my enum:
typedef enum logic [6:2] {
LOAD = 5'b00_000, LOAD_FP = 5'b00_001, CUSTOM_0 = 5'b00_010, MISC_MEM = 5'b00_011, OP_IMM = 5'b00_100, AUIPC = 5'b00_101, OP_IMM_32 = 5'b00_110, OP_48_1 = 5'b00_111,
STORE = 5'b01_000, STORE_FP = 5'b01_001, CUSTOM_1 = 5'b01_010, AMO = 5'b01_011, OP = 5'b01_100, LUI = 5'b01_101, OP_32 = 5'b01_110, OP_64 = 5'b01_111,
MADD = 5'b10_000, MSUB = 5'b10_001, NMSUB = 5'b10_010, NMADD = 5'b10_011, OP_FP = 5'b10_100, RESERVED_6 = 5'b10_101, CUSTOM_2 = 5'b10_110, OP_48_2 = 5'b10_111,
BRANCH = 5'b11_000, JALR = 5'b11_001, RESERVED_A = 5'b11_010, JAL = 5'b11_011, SYSTEM = 5'b11_100, RESERVED_D = 5'b11_101, CUSTOM_3 = 5'b11_110, OP_80 = 5'b11_111
} base_opcode_map;
If not can somebody tell me the kind of pattern I need to follow?
There are a few things you can do. You can use a let construct
let I_TYPE = opcode inside {LOAD, LOAD_FP, MISC_MEM, OP_IMM, OP_IMM_32};
let S_TYPE = opcode inside {STORE, STORE_FP, AMO};
...
let is a shorthand for defining a simple function
function bit I_TYPE;
return opcode inside {LOAD, LOAD_FP, MISC_MEM, OP_IMM, OP_IMM_32};
endfunction
function bit S_TYPE;
return opcode inside {STORE, STORE_FP, AMO};
endfunction
Then you can write a case statement
always # * begin
case (1'b1)
I_TYPE : begin
imm[0] <= inst[20];
imm[4:1] <= inst[24:21];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
S_TYPE : begin
imm[0] <= inst[7];
imm[4:1] <= inst[11:8];
imm[10:5] <= inst[30:25];
imm[31:11] <= inst[31];
end
// ...continued
default :
imm <= 0;
endcase
end

(vhdl) expected type = current type type error

I keep getting an error that says:
line 25: type error near num_values ; current type unsigned; expected
type unsigned.
It is already the type that is supposed to be, and I think it is same in bit length and declared alright, what am I doing wrong here?
The code is about implementation of fifo queue structure.
<Queue.vhd>
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Queue is
port (
-- clock
clk: in std_logic;
-- input
push: in std_logic;
push_data: in std_logic_vector(31 downto 0);
pop: in std_logic;
-- output
pop_data: out std_logic_vector(31 downto 0);
num_values: out unsigned(31 downto 0)
);
end entity;
architecture Behavioral of Queue is
type items is array(0 to 31) of std_logic_vector(31 downto 0);
signal manager : items := (others => (others => '0'));
signal push_idx, pop_idx : integer := 0;
begin
process(clk) is
variable howmany : integer := 0;
begin
if rising_edge(clk) then
if (push = '1') then
manager(push_idx) <= push_data;
push_idx <= push_idx + 1;
howmany := howmany + 1;
end if;
if (pop = '1') then
if (howmany /= 0) then
pop_data <= manager(pop_idx);
pop_idx <= pop_idx + 1;
howmany := howmany - 1;
end if;
else
pop_data <= std_logic_vector(to_unsigned(0,pop_data'length));
end if;
if (push_idx = 31) then
push_idx <= 0;
end if;
if (pop_idx = 31) then
pop_idx <= 0;
end if;
num_values <= to_unsigned(howmany,32);
end if;
end process;
end architecture;
<QueueTb.vhd>
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity QueueTb is
end entity;
architecture sim of QueueTb is
constant ClockFrequency : integer := 100e6;
constant ClockPeriod : time := 1000ms / ClockFrequency;
signal clk : std_logic := '0';
signal push, pop : std_logic := '0';
signal num_values : unsigned(31 downto 0);
signal push_data, pop_data : std_logic_vector(31 downto 0) := (others =>'0');
begin
UUT : entity work.Queue(Behavioral)
port map(
clk => clk,
push => push,
pop => pop,
num_values => num_values, <=== this is where error occurs!
push_data => push_data,
pop_data => pop_data);
clk <= not clk after ClockPeriod / 2;
process is
begin
wait for 10 ns;
push <= '1';
push_data <= conv_std_logic_vector(123,32);
wait for 10 ns;
push_data <= conv_std_logic_vector(456,32);
wait for 10 ns;
push <= '0';
push_data <= conv_std_logic_vector(0,32);
pop <= '1';
wait for 10 ns;
pop <= '0';
push <= '1';
push_data <= conv_std_logic_vector(789,32);
wait for 10 ns;
push <= '0';
pop <= '1';
wait for 80 ns;
end process;
end architecture;
What am I doing wrong here??
In the Queue entity you are using ieee.numeric_std and in the QueueTB you are using ieee.std_logic_arith . Both define different unsigned types.
Delete std_logic_arith from the testbench as it is not a standard VHDL library and use numeric_std instead.

Can we use an "if" before with-select -VHDL

I have a code like the following,
with current_display select
char_output <= hours1 & '1' when "0111",
hours2 & '1' when "1011",
mins1 & '1' when "1101",
mins2 & '1' when "1110",
"00000" when others;
but I would like to add two or more options to selecting the display of 7-segment. Adding only one option I make this one,
with set_alarm_switch & current_display select
char_output <= hours1 & '1' when "00111",
hours2 & '1' when "01011",
mins1 & '1' when "01101",
mins2 & '1' when "01110",
alarm_hours1 & '1' when "10111",
alarm_hours2 & '1' when "11011",
alarm_mins1 & '1' when "11101",
alarm_mins2 & '1' when "11110",
"00000" when others;
I wonder if I make this same coding with some "if" statements because if i were to add these guys another property, then I would have a complicated code.
I think all the current answers miss the question: "[...] make this same coding with some "if" statements [...]."
Your current VHDL describes your desired circuit using a parallel assignment statement (with-select). You can easily convert this into multiple sequential statements inside a parallel process:
assign_output_p : process (
-- VHDL-2008: use "all" instead of each signal name
set_alarm_switch,
current_display,
hours1,
hours2,
mins1,
mins2,
alarm_hours1,
alarm_hours2,
alarm_mins1,
alarm_mins2
)
begin
-- default assignment
char_output <= (others => '0');
if (set_alarm_switch = '1') then
-- set alarm case
case (current_display) is
when "0111" =>
char_output <= alarm_hours1 & '1';
when "1011" =>
char_output <= alarm_hours2 & '1';
when "1101" =>
char_output <= alarm_mins1 & '1';
when "1110" =>
char_output <= alarm_mins2 & '1';
when others =>
-- case for other current_display values
-- including XUZ etc.
null;
end case;
else
-- default case
case (current_display) is
when "0111" =>
char_output <= hours1 & '1';
when "1011" =>
char_output <= hours2 & '1';
when "1101" =>
char_output <= mins1 & '1';
when "1110" =>
char_output <= mins2 & '1';
when others =>
-- case for other current_display values
-- including XUZ etc.
null;
end case;
end if;
end process assign_output_p;
Also, I think you should evaluate if this big multiplexer makes sense in your application. Seven-segment displays are not that timing critical, so I advise to include a register stage at some point.
Many companies choose to have a policy about this:
Register inputs, leave outputs combinational => assumption that the next module will register them.
Combinational inputs, register outputs => assumption that the previous module has registered outputs.
Personally I would treat each 7 segment display as its own signal. You might have good reasons not to do this, but it makes the most sense to me. So your code might look like this:
seg3 <= hours_tens_time when current_display = '1' else hours_tens_alarm;
seg2 <= hours_ones_time when current_display = '1' else hours_ones_alarm;
seg1 <= mins_tens_time when current_display = '1' else mins_tens_alarm;
seg0 <= mins_ones_time when current_display = '1' else mins_ones_alarm;
This way, you can add more signals as you want to on seg3, 2, 1, 0, if you want to add a stopwatch or whatever you can do that, just expand this conditional assignment above. Give your signals more meaningful names too. hours1 hours2 doesn't mean anything.

VHDL Saving input value into another signal

I have a question for my VHDL code. My entire code has to do the following:
input = Minutes + hours + clk
output = AFTER 1 minute: minuten = minuten + 1 (and if needed hours += 1)
So I built a counter, which counts (well for simulation easyness to 1/10th of a second instead of a minute) clock periods untill one minute is over. Then it raises the minute by 1, and send that to the output. I got one problem however: due to setup violation I can't simulate the synthesis well. I thought this violation was in the line: min_save = minutes. I think that it's impossible to save the input minutes immediately, so I thought: let's build another counter, which counts 1 clock period, and then saves it.
So my 2 questions:
Does this indeed solve the setup violation?
If so: why does the signal setup have no value. It has a value of undefined. What do i do wrong?
If not: why not, and how can I solve this then?
CODE:
architecture behaviour of internclk_u is
begin
process (minuten)
begin -- switching input minutes to binary.
minintern(6) <= minuten(0);
minintern(5) <= minuten(1);
minintern(4) <= minuten(2);
minintern(3) <= minuten(3);
minintern(2) <= minuten(4);
minintern(1) <= minuten(5);
minintern(0) <= minuten(6);
end process;
process (uren)
begin -- switching input hours to binary
uurintern(5) <= uren(0);
uurintern(4) <= uren(1);
uurintern(3) <= uren(2);
uurintern(2) <= uren(3);
uurintern(1) <= uren(4);
uurintern(0) <= uren(5);
end process;
process (clk)
begin
setup <= '0';
if(clk'event and clk = '1') then
if(setup < '1') then
setup <= '1';
else
setup <= setup;
if(min_save = minutes) then
count <= new_count;
else
min_save <= minutes;
count <= (others => '0');
end if;
end if;
end if;
end process;
process (count, minintern)
begin -- count one minute (now its 0.1 second)
if(count < F/10 ) then
new_count <= count + 1;
intern_out <= minintern;
uurintern_out <= uurintern;
else
case minintern is -- Calculate new value for output
when "0001001" => intern_out <= "0010000";
uurintern_out <= uurintern;
when "0011001" => intern_out <= "0100000";
uurintern_out <= uurintern;
when "0101001" => intern_out <= "0110000";
uurintern_out <= uurintern;
when "0111001" => intern_out <= "1000000";
uurintern_out <= uurintern;
when "1001001" => intern_out <= "1010000";
uurintern_out <= uurintern;
when "1011001" => intern_out <= "0000000";
case uurintern is
when "001001" => uurintern_out <= "010000";
when "011001" => uurintern_out <= "100000";
when others => uurintern_out <= uurintern + 1;
end case;
when others => intern_out <= minintern + 1;
uurintern_out <= uurintern;
end case;
new_count <= count;
setup <= '0';
end if;
end process;
process (intern_out) -- Reversing signals for next blocks in system
begin
interne_tijd_m(6) <= intern_out(0);
interne_tijd_m(5) <= intern_out(1);
interne_tijd_m(4) <= intern_out(2);
interne_tijd_m(3) <= intern_out(3);
interne_tijd_m(2) <= intern_out(4);
interne_tijd_m(1) <= intern_out(5);
interne_tijd_m(0) <= intern_out(6);
end process;
process (uurintern_out)
begin -- Reversing signals for next blocks in system
interne_tijd_u(5) <= uurintern_out(0);
interne_tijd_u(4) <= uurintern_out(1);
interne_tijd_u(3) <= uurintern_out(2);
interne_tijd_u(2) <= uurintern_out(3);
interne_tijd_u(1) <= uurintern_out(4);
interne_tijd_u(0) <= uurintern_out(5);
end process;
end behaviour;
Remarks:
ignore the 2 case statements; this is because the inputsignals are not binary coded; they are reversed. Besides that: it doesnt count 1,2,4,8,16 etc; it counts: 1,2,4,8,10,20 etc.
EDIT
I put in the whole architecture now.
The error message I received was something like: "Setup time violations occured(?)". So I believe I cant save the input minutes immediately when I receive minutes. Thats why I tried to program in the setup signal. Hope you guys can help. This error gave me a headache and lots of frustration already:(
EDIT 2
Forget about the whole "setup" signal. A student-assistent pointed out to me that the saving of the input doesnt make any sense. So my updated question is: How can I properly save the input signal/value into another signal?
Your code is really a mess, and it's very difficult to debug... :-(
I think that the problem is due to the fact that you have a multiple definition of the signal setup. Moreover the first time is defined inside a clocked process (even if the setup <= '0' is outside the if statement). The second time is defined inside another process that is not clocked. I think that the synthesis tool doesn't know how to proceed exactly. In the simulation of the RTL code you should normally see some glitches on the setup signal. I also think that the type of setup is set_logic. Try to change it to std_ulogic. The simulation tool will not compile your code since this type is unresolved. Fix the code and then go back to std_logic.
Another thing: you wrote if setup < '1' then: this sounds very strange to me (I didn't know that it was accepted). I prefer to write if setup /= '1' then: it is much more easier to read this kind of code...

How to connect components of VHDL code

I have 2 components that have worked separately in simulation, but now I'm confused on how to implement the design onto my board. I have one design that is a binary to 7-segment display, and another that is a counter that counts upwards in seconds.
How do I connect these two to work together to show values onto a basys2 board?
Code for timer
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY clock IS
port(reset,clk,start,stop:in std_logic;
min,sec:out integer);
end clock;
architecture behaviour of clock is
begin
process(reset,clk,start,stop)
variable tempmin,tempsec:integer:=0;
begin
if(reset='1')then
tempmin:=0;
tempsec:=0;
elsif(stop='1')then
min<=tempmin;
sec<=tempsec;
elsif(start='1')then
if(rising_edge(clk))then
tempsec:=tempsec+1;
if(tempsec=60)then
tempsec:=0;
tempmin:=tempmin+1;
if(tempmin=10)then
tempmin:=0;
end if;
end if;
end if;
end if;
min<=tempmin;
sec<=tempsec;
end process;
end behaviour;
Code for binary to 7-segment
architecture Behavioral of SevenSegment is
begin
process (seg_value)
begin
if (seg_value = "0000") then
seg <= "0000001";
an <= "1100";
elsif (seg_value = "0001") then
seg <= "1001111";
an <= "1100";
elsif (seg_value = "0010") then
seg <= "0010010";
an <= "1100";
elsif (seg_value = "0011") then
seg <= "0000110";
an <= "1100";
elsif (seg_value = "0100") then
seg <= "1001100";
an <= "1100";
elsif (seg_value = "0101") then
seg <= "0100100";
an <= "1100";
elsif (seg_value = "0110") then
seg <= "0100000";
an <= "1100";
elsif (seg_value = "0111") then
seg <= "0001111";
an <= "1100";
elsif (seg_value = "1000") then
seg <= "0000000";
an <= "1100";
elsif (seg_value = "1001") then
seg <= "0000100";
an <= "1100";
end if;
end process;
end Behavioral;
Look up the syntax for component instantiation (or entity instantion) in your VHDL textbook. Emacs VHDL mode and Sigasi provide power-templates so you don't have to type so much code: http://www.sigasi.com/screencast/entity-instantiation