nbit Bitslice ALU with For/IF Generate in VHDL - if-statement

I'm designing a n-bit bitslice ALU with GENERATE and I wrote this code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
ENTITY ALU IS
GENERIC (n : integer := 8);
PORT (A,B : IN std_logic_vector(n-1 DOWNTO 0);
funct : IN std_logic_vector (2 DOWNTO 0);
clk,nrst : IN std_logic;
Z : OUT std_logic_vector (n-1 DOWNTO 0);
ov,cout : OUT std_logic);
END ALU;
ARCHITECTURE bitSlice OF ALU IS
SIGNAL C : std_logic_vector (0 TO n);
SIGNAL temp : std_logic_vector (n-1 DOWNTO 0);
BEGIN
L1:IF nrst = '1' GENERATE
L2:IF funct = "000" GENERATE Z <= A;
END GENERATE L2;
L3:IF funct = "001" GENERATE Z <= B;
END GENERATE L3;
L4:IF funct = "010" GENERATE
c(0) <= '0';
cout <= C(n);
ov <= C(n);
L5: FOR i IN 0 TO n-1 GENERATE
Z(i) <= (A(i) XOR B(i) XOR C(i));
C(i+1) <= (A(i) AND B(i)) OR
(A(i) AND C(i)) OR
(B(i) AND C(i));
END GENERATE L5;
END GENERATE L4;
L6:IF funct = "011" GENERATE
c(0) <= '0';
cout <= C(n);
ov <= C(n);
temp <= std_logic_vector(signed(NOT(b))+1);
L7: FOR i IN 0 TO n-1 GENERATE
Z(i) <= (A(i) XOR temp(i) XOR C(i));
C(i+1) <= (A(i) AND temp(i)) OR
(A(i) AND C(i)) OR
(B(i) AND C(i));
END GENERATE L7;
END GENERATE L6;
L8:IF funct = "100" GENERATE Z <= A(n-1 DOWNTO 0) & '0';
END GENERATE L8;
L9:IF funct = "101" GENERATE Z <= B(n-1 DOWNTO 0) & '0';
END GENERATE L9;
L10:IF funct = "110" GENERATE Z <= '0' & a(n DOWNTO 1);
END GENERATE L10;
L11:IF funct = "111" GENERATE Z <= '0' & b(n DOWNTO 1);
END GENERATE L11;
END GENERATE L1;
END bitSlice;
It compiles alright but it doesn't work, although there are a bunch of warnings in generate blocks that says IF statement must be static. I wonder where I made a mistake.

You are asking the tools to generate different hardware according to a port whose input value is unknown till runtime. That won't work!
Making "funct" a generic input will allow you to use the Generates successfully, but the functionality will be fixed at elaborationtime.
Generating ALL the hardware and using "funct" to multiplex between different generated results is probably closer to what you want.

Generate is used to choose between different bits of hardware being "made". Your funct is an input, which can therefore change during operation. There is no way to change the actual hardware you've make at that point.
You need to choose between different sets of results from all the hardware based on funct - wrap your if..generates in a clocked process and change them to if..thens - and go from there.

You could use the WHEN or SELECT statement instead of GENERATE in this kind of implementation.
Your code has another problem: You are implementing a combinational circuit but you didn't specify the complete LUTs, which will cause the inference of latches. For example, you didn't specify the output values for nrst='0' (among several other signals/cases).

Related

Trying to finish adder need if statement to change carry

I have got an adder with inputs a and b in std_logic_vector(data_width-1) downto 0 and out output of sum std_logic_vector(data_width) downto 0. I am trying to use an if statement to bypass the carry bit and add it to the sum
I just need help with the syntax the idea is if the carry's MSB is 1 the it adds 1 to the answer(sum)
architecture v1 of adding is
begin
adding : process (A, B) is
variable CI : std_logic_vector((DATA_WIDTH) downto 0);
variable SUMMER : std_logic_vector((DATA_WIDTH) downto 0);
begin
SUMMER := A xor B;
CI := A and B;
CI_msb <= CI(CI'left);
if CI_msb = '1' then
SUMMER = SUMMER + 1;
end if;
I am getting syntax errors regarding (summer = summer + 1;) I am not familiar enough to know what is needed.
To assign a value to a variable you have to use :=, so the code becomes SUMMER := SUMMER + 1;.

How to/Can you use if statement to an Assert Report Severity Statement in VHDL Testbench?

Okay. So to say why I'm asking this question. We have been told to develop the system that can work out the system that can resolve the formula:
O <= (A*3 + B*C)/D + C +5
There is a two cycle propagation delay in the system as it currently stands. However as it gets more complicated as we develop it, so I'm using a constant propagation_delay to represent how the delay can change.
There is a much simpler way to make a self checking test bench for this system, have two processes, one that inputs the test vectors, and one that waits for the delay, and then starts checking. However we were told that there was a more tricky way of doing it which involved only one process. I have decided to attempt this way as I enjoy VHDL a whole deal so I want to explore it as much I can!
Another constraint from the lecturer was that there had to be change every clock cycle.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY algorith_TB IS
END algorith_TB;
ARCHITECTURE behavior OF algorith_TB IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT algorithm
PORT(
A : IN std_logic_vector(15 downto 0);
B : IN std_logic_vector(15 downto 0);
C : IN std_logic_vector(15 downto 0);
D : IN std_logic_vector(15 downto 0);
O : OUT std_logic_vector(31 downto 0);
clk : IN std_logic;
rst : IN std_logic
);
END COMPONENT;
--Inputs
signal A : std_logic_vector(15 downto 0); --:= (others => '0');
signal B : std_logic_vector(15 downto 0); --:= (others => '0');
signal C : std_logic_vector(15 downto 0); --:= (others => '0');
signal D : std_logic_vector(15 downto 0); --:= (others => '0');
signal clk : std_logic; --:= '0';
signal rst : std_logic; --:= '0';
--Outputs
signal O : std_logic_vector(31 downto 0);
-- Delay Constants Definition
constant propagation_delay : integer := 2;
constant num_vectors : integer := 5;
-- Clock period definitions
constant clk_period : time := 120 ns;
type test_vector is record
A : STD_LOGIC_VECTOR(15 downto 0);
B : STD_LOGIC_VECTOR(15 downto 0);
C : STD_LOGIC_VECTOR(15 downto 0);
D : STD_LOGIC_VECTOR(15 downto 0);
O : STD_LOGIC_VECTOR(31 downto 0);
end record;
type test_vector_array is array
(natural range<>) of test_vector;
constant test_vectors : test_vector_array := (
-- A B C D O
(x"0001", x"0002", x"0003", x"0004", x"0000000A") ,
(x"AAAA", x"0202", x"4131", x"4123", x"00004340") ,
(x"0001", x"0003", x"0005", x"0007", x"0000000C") ,
(x"AAAA", x"0202", x"4131", x"4123", x"00004340") ,
(x"0001", x"0003", x"0005", x"0007", x"0000000C") );
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: algorithm PORT MAP (
A => A,
B => B,
C => C,
D => D,
O => O,
clk => clk,
rst => rst
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 500 ns;
rst <= '1'; -- initial reset
wait for clk_period;
rst <= '0';
wait for clk_period*10; -- warm up period
wait until falling_edge(clk); -- resynchronise with falling edge
for i in 0 to 4 loop -- cycle through test vectors
if (i < num_vectors) then
A <= test_vectors(i).A;
B <= test_vectors(i).B;
C <= test_vectors(i).C;
D <= test_vectors(i).D;
wait for clk_period;
end if; -- end input loop if
if (i > propagation_delay) then -- pause for 2
assert (O = test_vectors(i-propagation_delay).O)
report "Test vector " & integer'image(i-propagation_delay) &
" failed for input A = " & integer'image(to_integer(unsigned(a))) &
"and b = " & integer'image(to_integer(unsigned(b))) &
" and C = " & integer'image(to_integer(unsigned(c))) &
"and D = " & integer'image(to_integer(unsigned(d)))
severity error;
end if; -- end assert check if
end loop; -- end for loop
wait;
end process;
END;
This works, in terms of simulation output. There is a two cycle delay between inputs and outputs.
However I am having a problem with the printing to console as it allows that i = 2,3,4 are all correct. But says that i = 0 , 1 are incorrect. Which are the two input vectors where i < propogation_delay. I understand I'm facing a problem here but just can't figure out how to fix it.
One way I've thought of fixing it but I get a syntax error I can't fix is:
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 500 ns;
rst <= '1'; -- initial reset
wait for clk_period;
rst <= '0';
wait for clk_period*10; -- warm up period
wait until falling_edge(clk); -- resynchronise with falling edge
for i in 0 to 4 loop -- cycle through test vectors
if (i < num_vectors) then
A <= test_vectors(i).A;
B <= test_vectors(i).B;
C <= test_vectors(i).C;
D <= test_vectors(i).D;
wait for clk_period;
end if; -- end input loop if
if (i > propagation_delay) then -- pause for 2
assert (O = test_vectors(i-propagation_delay).O)
end if; -- end assert check if
if (i - propagation_delay < 0) then
report "Test vector " & integer'image(i) &
" failed for input A = " & integer'image(to_integer(unsigned(a))) &
"and b = " & integer'image(to_integer(unsigned(b))) &
" and C = " & integer'image(to_integer(unsigned(c))) &
"and D = " & integer'image(to_integer(unsigned(d)))
severity error;
else
report "Test vector " & integer'image(i-propagation_delay) &
" failed for input A = " & integer'image(to_integer(unsigned(a))) &
"and b = " & integer'image(to_integer(unsigned(b))) &
" and C = " & integer'image(to_integer(unsigned(c))) &
"and D = " & integer'image(to_integer(unsigned(d)))
severity error;
end if; -- end report if
end loop; -- end for loop
wait;
end process;
END;
But I get a syntax error on the line
end if; -- end assert check if
I am trying to say if it is smaller then prop delay then check what is now, otherwise check i-prop.
Any ideas on how to work with this syntax or can you not split up the assert/report/severity?
Thanks for taking time to read guys!

Strange behavior of VHDL if statement

I was stucked in a strange problem with VHDL if statement when I was working on my project. Although I fixed it, I still don't understand why it happened. I stimulated my code using ModelSPIM. Before I changed the code, I expected rd <= inst (20 downto 16); when RegDst = '1', but it gave me rd <= inst (15 downto 11);. I have checked RegDst was really equal to 0, but it gave me the wrong assignment. After I changed the code, everythings became normal. What is the difference between them ?
Before:
fetch: process(inst)
begin
if( inst = x"0000_0000" ) then -- end of program
endRun <= '1';
else
endRun <= '0';
opcode <= inst (31 downto 26);
rs <= inst (25 downto 21);
rt <= inst (20 downto 16);
if( RegDst = '1' ) then
rd <= inst (15 downto 11);
else
rd <= inst (20 downto 16);
end if;
funct <= inst (5 downto 0);
offset <= inst (15 downto 0);
jsec <= inst (25 downto 0);
end if;
end process fetch;
After:
fetch: process(inst)
begin
if( inst = x"0000_0000" ) then -- end of program
endRun <= '1';
else
endRun <= '0';
opcode <= inst (31 downto 26);
rs <= inst (25 downto 21);
rt <= inst (20 downto 16);
funct <= inst (5 downto 0);
offset <= inst (15 downto 0);
jsec <= inst (25 downto 0);
end if;
end process fetch;
rd <= inst (15 downto 11) when (RegDst = '1') else
inst(20 downto 16); -- RegDst mux
It is a problem with your sensitivity list. The sensitivity list is the list of signal in the parentheses after process. A process is executed when an event occurs on any signal in it's sensitivity list.
In your case, only inst was in your sensitivity list. Thus, when regDst would change from '0' to '1', the process would not be executed (if inst didn't change) and rd would not update.
In your second approach, the statement is not in a process, thus is not affected by sensitivity list (to be exact, all signals involved in an out of process statement are considered it it's sensitivity list). Should you add redDst in the sensitivity list, you would have the same results:
process(inst, regDst)
Note that missing signals in sensitivity list is a very common source of mismatch between simulation and implementation since all tools I know ignore them for implementation. If you use VHDL-2008, you can use the keyword all in your sensitivity list, which implies exactly what you think.

VHDL If/Else statement

I am trying to work on a lab for a school project. we are supposed to be eventually making a program that displays signed integer values to an altera board. This is one of the steps along the way and i am stuck. I cant figure out why this if/else statement wont compile, I am new to VHDL, please help.
-----------------------------------------------------------------
-- circuit for converting a 4-bit signed integer
-- to a 1-bit sign and a 4-bit absolute value
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity sgnabs4 is
port (X : in std_logic_vector(3 downto 0);
sgn : out std_logic;
Xabs : out std_logic_vector(3 downto 0));
end sgnabs4;
architecture sgnabs4_arch of sgnabs4 is
component twos_complement4 is
port (A : in std_logic_vector(3 downto 0);
T : out std_logic_vector(3 downto 0));
end component twos_complement4;
-- you may define internal signals here as you feel necessary
signal That: std_logic_vector(3 downto 0);
signal Ahat: std_logic_vector(3 downto 0);
begin
twos_complement4_0: twos_complement4
port map(T => That, A=> Ahat);
sgn <= That(3);
if (sgn = '1') then
sgn => Xabs(3);
Xabs(2) <= not X(2);
Xabs(1) <= not X(1);
Xabs(0) <= not X(0);
else
Xabs(3) <= '0';
Xabs(2) <= X(2);
Xabs(1) <= X(1);
Xabs(0) <= X(0);
end if;
end sgnabs4_arch;
Andy's answer may be valid, but it doesn't explain what's wrong with yours at all. So:
As sebs pointed out in the comments, your if statement needs to be in a process. if statements are sequential; only concurrent statements are allowed outside processes in architecture bodies.
While the two fixes sebs pointed out may allow your code to compile (depends on how you handle another bit that I'll get to in a minute), it still won't work.
Your component instance twos_complement4_0 has Ahat mapped to its input port and That mapped to its output port, but you don't assign a value to Ahat anywhere in your code, so what will That be? Probably not anything useful. If you copied and pasted this, you need to understand what it does to be able to modify it appropriately. Look for a tutorial, specifically on component instantiation and port mapping.
Did you also mean to leave the line sgn <= That(3);? You can't drive sgn from multiple places. The process is one, the concurrent statement appears to be intended to be another (though maybe not - hard to tell). This won't work.
It looks like what you're trying to do is:
get the two's complement of your input.
If the input is negative, use the two's complement, else use the original number (and output the appropriate value on sgn).
The closest thing to your original code that does that would be:
architecture sgnabs4_arch of sgnabs4 is
component twos_complement4 is
port (A : in std_logic_vector(3 downto 0);
T : out std_logic_vector(3 downto 0));
end component twos_complement4;
signal tmp : std_logic_vector(3 downto 0);
begin
twos_complement4_0 : twos_complement4
port map (A => X, T => tmp);
sgn <= X(3);
process (X, tmp)
begin
if (X(3) = '1') then
Xabs <= tmp;
else
Xabs <= X;
end if;
end process;
end sgnabs4_arch;
tmp is the inverse of X. If X is negative (i.e. its sign bit is '1'), output the inverse, otherwise output X. This may not be the most efficient way to accomplish this task, as Andy alludes to, but it should work, and may be what you intended.
If you just need a quick solution, you can take this:
-----------------------------------------------------------------
-- circuit for converting a 4-bit signed integer
-- to a 1-bit sign and a 4-bit absolute value
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity sgnabs4 is
port (X : in std_logic_vector(3 downto 0);
sgn : out std_logic;
Xabs : out std_logic_vector(3 downto 0));
end sgnabs4;
architecture sgnabs4_arch of sgnabs4 is
begin
process(X)
variable tmp : signed(3 downto 0);
begin
tmp := signed(X);
if tmp < 0 then
sgn <= '1';
tmp := -tmp;
Xabs <= std_logic_vector(tmp);
else
sgn <= '0';
Xabs <= std_logic_vector(tmp);
end if;
end process;
end sgnabs4_arch;
If you rather want to understand, how arithmetic works, please refer to Wikipedia first:
http://en.wikipedia.org/wiki/Two%27s_complement
If you want to learn VHDL, the best way is to look for a tutorial and then make specific questions.

How can i generate a pulse train to give output in common way?

I am working on generating a 40 bit length pulse train. I also must be able to adjust the frequency. I tried to make a new low frequency clock and i make a new counter which counts on it's rising edges and give an high output and terminating after 40 bit. It's not working. I tried some other methods. They are not, too.
For example;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;
entity con40 is port(clk:in std_ulogic; q:out std_ulogic);
end entity con40;
architecture Behaviour of con40 is
constant s:std_ulogic_vector:="11111111111111111111111111111111";
signal i:unsigned(4 downto 0):="00000";
signal en:std_logic:='1';
signal reset:std_logic:='0';
begin
q<=s(to_integer(i));
process(reset,clk) is begin
if reset='1' then
i<=(others=>'0');
elsif rising_edge(clk) then
if en='1' then
i<=i+1;
end if;
end if;
end process;
end architecture Behaviour;
There is 32-bit length in this code but i wanna make 40 bit but whatever, this is not working too. I think methods for such a pulse train must be common and they are being used widely. But hey! unluckily i can find nothing useful.
I took the liberty of moving en and reset to port signals, also changed your constant to a recognizable 40 bit value, and specified the range to make it a locally static constant.
The issue with your counter is that it isn't big enough to address 40 bits. You have i specified as a 5 bit value while 40 bits requires a 6 bit counter.
I also added a second architecture here with i as an integer type signal. With i as either an unsigned value or an integer type you likely need to roll over the i counter at 39 ("100111") when the first position is 0 ("000000").
library ieee;
use ieee.std_logic_1164.all;
entity con40 is
port(
reset: in std_ulogic;
clk: in std_ulogic;
en: in std_ulogic;
q: out std_ulogic
);
end entity con40;
architecture foo of con40 is
constant s: std_ulogic_vector (0 to 39) := x"feedfacedb";
signal i: natural range 0 to 39;
begin
q <= s(i);
process (reset, clk)
begin
if reset = '1' then
i <= 0;
elsif rising_edge(clk) and en = '1' then
if i = 39 then
i <= 0;
else
i <= i + 1;
end if;
end if;
end process;
end architecture;
library ieee;
use ieee.numeric_std.all;
architecture behave of con40 is
constant s: std_ulogic_vector (0 to 39) := x"feedfacedb";
signal i: unsigned (5 downto 0);
begin
q <= s(to_integer(i));
process (reset, clk)
begin
if reset = '1' then
i <= "000000";
elsif rising_edge(clk) and en = '1' then
if i = "100111" then
i <= "000000";
else
i <= i + 1;
end if;
end if;
end process;
end architecture;
I also did a quick and dirty test bench:
library ieee;
use ieee.std_logic_1164.all;
entity tb_con40 is
end entity;
architecture foo of tb_con40 is
signal clk: std_ulogic := '0';
signal reset: std_ulogic := '1';
signal en: std_ulogic := '0';
signal q: std_ulogic;
begin
DUT:
entity work.con40
port map (
reset => reset,
clk => clk,
en => en,
q => q
);
CLOCK:
process
begin
for i in 0 to 46 loop
wait for 20 ns;
clk <= not clk;
wait for 20 ns;
clk <= not clk;
end loop;
wait;
end process;
STIMULUS1:
reset <= '0' after 40 ns;
STIMULUS2:
en <= '1' after 60 ns;
end architecture;
Which can demonstrate the correct output:
addendum in response to comment question
The pattern X"FEEDFACEDB" is 40 bits long and was substituted for the 32 all '1's value for constant s to demonstrate that you are actually addressing individual elements of the s array value.
To stop the pulse train fro recurring:
For architecture foo (using an integer type for i):
elsif rising_edge(clk) and en = '1' then
-- if i = 39 then
-- i <= 0;
-- else
if i /= 39 then -- added
i <= i + 1;
end if;
This stops the counter from operating when it reaches 39.
For architecture behave (using an unsigned type for i):
elsif rising_edge(clk) and en = '1' then
-- if i = "100111" then
-- i <= "000000";
-- else
if i /= "100111" then -- added
i <= i + 1;
end if;
end if;
Both architectures behave identically stopping the i counter at 39 ("100111").
The counter can be shown to have stopped by simulating:
Without adding an additional control input the only way to get the pulse stream to occur a second time would be by invoking reseet.
The following code could be a simple implementation to generate pulse trains. This module requires a start impulse (StartSequence) and acknowledges the generated sequence with 'SequenceCompleted'.
Instead of an state machine I use a basic RS flip flop with set = StartSequence and rst = SequenceCompleted_i. I also broke up the process into two processes:
state control - this can be extended to a full FSM if needed
used for counter(s)
Initially, the module emits PULSE_TRAIN(0) by default and also after each sequence generation. So if you want to emit 40 ones otherwise zero set PULSE_TRAIN := (0 => '0', 1 to 40 => '1')
This module is variable in the bit count of PULSE_TRAIN, so I needed to include a function called log2ceil, which calculates the 2s logarithm aka needed bits from PULSE_TRAIN's length attribute.
So in case of 'length = 41 bits Counter_us has a range of (5 downto 0).
entity PulseTrain is
generic (
PULSE_TRAIN : STD_LOGIC_VECTOR
);
port (
Clock : in STD_LOGIC;
StartSequence : in STD_LOGIC;
SequenceCompleted : out STD_LOGIC;
Output : out STD_LOGIC
);
end entity;
architecture rtl of PulseTrain is
function log2ceil(arg : POSITIVE) return NATURAL is
variable tmp : POSITIVE := 1;
variable log : NATURAL := 0;
begin
if arg = 1 then return 0; end if;
while arg > tmp loop
tmp := tmp * 2;
log := log + 1;
end loop;
return log;
end function;
signal State : STD_LOGIC := '0';
signal Counter_us : UNSIGNED(log2ceil(PULSE_TRAIN'length) - 1 downto 0) := (others => '0');
signal SequenceCompleted_i : STD_LOGIC;
begin
process(Clock) is
begin
if rising_edge(Clock) then
if (StartSequence = '1') then
State <= '1';
elsif (SequenceCompleted_i = '1') then
State <= '0';
end if;
end if;
end process;
SequenceCompleted_i <= '1' when (Counter_us = (PULSE_TRAIN'length - 1)) else '0';
SequenceCompleted <= SequenceCompleted_i;
process(Clock)
begin
if rising_edge(Clock) then
if (State = '0') then
Counter_us <= (others => '0');
else
Counter_us <= Counter_us + 1;
end if;
end if;
end process;
Output <= PULSE_TRAIN(to_integer(Counter_us));
end;
As what #fru1tbat mentioned, it's not really clear what is "not working" and what you really intend to do. If you would really just want to generate a pulse train, one would think you want to generate a series of alternating '1' and '0', not all '1's like in the code you posted.
Also, the i counter just counts up, and can only be reset to '0' by use of the reset signal, which is fine as long as you intended it that way.
If you'd like to generate a train of '1's and '0's, you'd need something like this (not tested, but should be along these lines):
architecture behaviour of con40 is
constant trainLength:positive:=80;
signal i:unsigned(6 downto 0):=(others=>'0');
...
begin
process(reset,clk) is begin
if reset then
i<=(others=>'0');
q<='0';
elsif rising_edge(clk) then
q<='0'; -- default assignment.
-- Defaults to '0' when if-statement fails.
if i<trainLength then
i<=i+1;
q<=not q;
end if;
end if;
end process;
end architecture behaviour;
This gives you a single-shot pulse train, means there is no way to repeat generation of the pulse train unless you assert the reset signal again. This is fine if it's what you want, otherwise, you'll need more signals to cater for cases where you'd like to re-generate the pulse train without resetting.
Here, I'm assuming you'd like 40 HIGH pulses, which essentially makes the train length 80 clock cycles, not 40. Also, I'm assuming you want a 50% duty cycle, i.e. the HIGH and LOW times are equal. Depending on your requirements, you may need a pulse width that is longer or shorter.
With these assumptions in mind, you'd need at least a 7-bit counter to count 80 clocks. You may think of other better ways to do this as well, but this just comes off the top of my head, and is probably a good place to start.
If your tool doesn't yet support VHDL-2008's enhanced port modes (e.g. ability to read from out-mode ports), then you could declare q as having a buffer mode instead of out. If your tool doesn't support buffer port modes, then you can declare an internal signal and use it for your logic. E.g.:
signal i_q: std_ulogic;
...
i_q<=not i_q; -- use internal signal for logic instead.
q<=i_q; -- drive output from internal signal.
To adjust the frequency, simply supply a higher or lower frequency into your clk input. This can be generated from another PLL, or a frequency divider, or any other oscillating circuitry you have available. Just supply its output into your clk.
Hope this helps.