using procedures

M

Michel Bieleveld

I am confused howto make use of procedures. It was my understanding
that i could use wait statements within the body of procedure. Yet my
vhdl code is not being synthesized. Can someone help me with this ? or
give good online reference/tutorial concerning procedures ?

With regards,

Michel Bieleveld.

architecture RTL of ax88796 is
..

Procedure AX_write (AX_reg : in std_logic_vector(9 downto 0);
AX_data : in
std_logic_vector(15 downto 0)) is
begin
Write_ax_loop : loop
..
wait until CLK'EVENT and CLK = '1';
exit Write_ax_loop when nRST = '0';
..
end loop;
end AX_Write;

COMB_PROC: process (CState,Div2ms)
begin
..
AX_Write(reg_dcr,init_dcr);
..
end process;
end RTL;
 
N

Nicolas Matringe

Michel Bieleveld a écrit:
I am confused howto make use of procedures. It was my understanding
that i could use wait statements within the body of procedure. Yet my
vhdl code is not being synthesized. Can someone help me with this ? or
give good online reference/tutorial concerning procedures ?

You cannot call a procedure with wait statements from within a process
with a sensitivity list.
 
M

Michel Bieleveld

Hmm since i was planning on calling the procedure within my
statemachine I think I have a problem. What I want is to make a
macro?/procedure to easily write values to a registe, do you have any
suggestions to solve my problem ?

How do people generally solve this problem , synchronizing the main
state machine with a write register state machine ?
 
N

Nicolas Matringe

Michel Bieleveld a écrit:
Hmm since i was planning on calling the procedure within my
statemachine I think I have a problem. What I want is to make a
macro?/procedure to easily write values to a registe, do you have any
suggestions to solve my problem ?

How do people generally solve this problem , synchronizing the main
state machine with a write register state machine ?

I never use procedures in synthesizable code.
Synchronization of state machines is usually done with signals...
I don't understand what you're trying to do so I can't help you any further
 
M

Michel Bieleveld

I am trying to improve my coding, what i have till so far is working
nicely. BUT since i need to initialize around 10 registers this would
mean i have to write down 10 * 2 states (like Boot4/Boot5 and
Boot6/Boot7). So now i am confused how to make the code more compact,
and more elegant. ( Like using a procedure)


COMB_PROC: process (CState,Div2ms,AX_Write_Ready,SD_OE)
begin
nCS <= '0';
nBHE <= '0';
case CState is
when Boot1 =>
AX_Write <= '0';
RESET <= '0';
Div2msReset <= '1';
NState <= Boot2;
when Boot2 =>
AX_Write <= '0';
RESET <= '1';
Div2msReset <= '0';
if ( Div2ms = '1') then
NState <= Boot3;
end if;
when Boot3 =>
AX_Write <= '0';
RESET <= '0';
Nstate <= Boot4;

when Boot4 =>
SA <= reg_dcr;
SD_out <= init_dcr;
SD_OE <= '1';
AX_Write <= '1';
Nstate <= Boot5;
when Boot5 =>
AX_Write <= '0';
if (AX_Write_Ready ='1') then
SD_OE <= '0';
NState <= Boot6;
else
SA <= reg_dcr;
SD_out <= init_dcr;
SD_OE <= '1';
end if;
when Boot6 =>
SA <= reg_rbcr0;
SD_out <= init_rbcr0;
SD_OE <= '1';
AX_Write <= '1';
NState <= Boot7;
when Boot7 =>
AX_Write <='0';
if (AX_Write_Ready ='1') then
SD_OE <= '0';
NState <= Boot8;
else
SA <= reg_rbcr0;
SD_out <= init_rbcr0;
SD_OE <= '1';
end if;
when Boot8 =>

end case;
end process;


WRITE_AX: process(CStateW,AX_Write)
begin
case CStateW is
when Write0 =>
nIOWR <= '1';
if (AX_Write='1') then
AX_Write_Ready<= '0';
NStateW <= Write1;
else
AX_Write_Ready<= '1';
end if;
when Write1 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NStateW <= Write2;
when Write2 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NstateW <= Write3;
when Write3 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NstateW <= Write4;
when Write4 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NstateW <= Write5;
when Write5 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NStateW <= Write6;
when Write6 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NstateW <= Write7;
when Write7 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NstateW <= Write8;
when Write8 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NStateW <= Write9;
when Write9 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NstateW <= Write10;
when Write10 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NStateW <= Write11;
when Write11 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NstateW <= Write12;
when Write12 =>
AX_Write_Ready <= '0';
nIOWR <= '1';
NStateW <= Write13;
when Write13 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NStateW <= Write0;
end case;
end process;




end RTL;
 
P

Pieter Hulshoff

Michel said:
I am trying to improve my coding, what i have till so far is working
nicely. BUT since i need to initialize around 10 registers this would
mean i have to write down 10 * 2 states (like Boot4/Boot5 and
Boot6/Boot7). So now i am confused how to make the code more compact,
and more elegant. ( Like using a procedure)

The code looks a tad scary ... 2 asynchronous state machines that send
information back and forth will often give interesting results in the
field. How about giving us the original problem you're trying to solve to
see if we can help you with it?

Regards,

Pieter Hulshoff
 
M

Michel Bieleveld

Yes I thought the code looked scary too ;) Although i *think* the
state machines are well synchronized. However I would love to see some
clean code.

So here is my problem:

I am communicating with another chip. To setup the other chip I need
to make a reset signal of 20ms and then set some registers.

For the communication I need to make a /IOWR pin low for 60ns and high
for at least 100ns. My result were the two main processes listed in my
previous post.

I have no idea to make it more beautiful and would love to hear some
suggestions of how my betters are doing this :)

With regards,

Michel.
 
J

Jeroen

Michel Bieleveld said:
Yes I thought the code looked scary too ;) Although i *think* the
state machines are well synchronized. However I would love to see some
clean code.

So here is my problem:

I am communicating with another chip. To setup the other chip I need
to make a reset signal of 20ms and then set some registers.

For the communication I need to make a /IOWR pin low for 60ns and high
for at least 100ns. My result were the two main processes listed in my
previous post.

I have no idea to make it more beautiful and would love to hear some
suggestions of how my betters are doing this :)

With regards,

Michel.

What I usually do is to use 2 state machines; one FSM takes care of
transferring the data to the external chip, the other (higher level) FSM
takes of what data should be sent. Both communiciate with each other with
signals. The interface to the lower level FSM is for example

data:std_logic_vector(7 downto 0);
start_write:std_logic;
write_done:std_logic;

The first FSM waits for 'start_write' to become '1' and starts the transfer.
When it's done, it sets 'write_done' to '1' and waits for 'start_write' to
become '0' again and sets 'write_done' to '0'. This is a two way handshake.
The higher level FSM just controls these signals.
In this way almostly duplicate logic in states is removed, and has some
analogy of procedures in a procedural language like C.
Depending on some factors, a full two way handshake is not neccessary, and
the control signals can be only one clock pulse wide.

To save even further on states, you can put all the initialisation data in a
big vector and use a counter to select the proper subvector.

Hope this helps,

Jeroen
 
P

Pieter Hulshoff

Michel said:
I am communicating with another chip. To setup the other chip I need
to make a reset signal of 20ms and then set some registers.

For the communication I need to make a /IOWR pin low for 60ns and high
for at least 100ns. My result were the two main processes listed in my
previous post.

Do you have any clock available to your design to synchronize things, and to
measure time with? What frequency is said clock running at?

I agree with Jeroen that it would be good to have one process that
communicates, and one that controls the information that needs to be
communicated. Both should be clocked. I know there are people out there
that have managed to get asynchronous designs working, but it's a
complicated design practice. :)

Regards,

Pieter Hulshoff
 
M

Michel Bieleveld

Yes this helps and this is what I already made. I was thinking of
using arrays to store the init data instead of one large vector. What
do you think is better ?
 
M

Michel Bieleveld

Yes I have a clock available and processes that i use to synchronize
the state machines, like (in short):

If Reset then CState <= Boot1;
If Clk get high then Cstate <= NState;

The frequency that i am targetting for at the moment is 80 MHz, I
don`t know if it will be reasonable but I hope it is. That is why i
wait 5 clocks (states) for the 60ns to let /IOWR low, and then 100ns ,
8 clocks(states) to make /IOWR high.

I agree about the asynchronous, so that is why i think i solved the
problem by using one combinatorial process, and one synchronizing
process for a state machine. This way it seems too me to garantee
synchronized state machines.

How can i reduce the very long sequence of when => in the following
code ?

I appreciate the help I get from all of you :)

With regards,

Michel.


WRITE_AX: process(CStateW,AX_Write)
begin
case CStateW is
when Write0 =>
nIOWR <= '1';
if (AX_Write='1') then
AX_Write_Ready<= '0';
NStateW <= Write1;
else
AX_Write_Ready<= '1';
end if;
when Write1 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NStateW <= Write2;
when Write2 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NstateW <= Write3;
when Write3 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NstateW <= Write4;
when Write4 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NstateW <= Write5;
when Write5 =>
nIOWR <= '0';
AX_Write_Ready<= '0';
NStateW <= Write6;
when Write6 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NstateW <= Write7;
when Write7 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NstateW <= Write8;
when Write8 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NStateW <= Write9;
when Write9 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NstateW <= Write10;
when Write10 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NStateW <= Write11;
when Write11 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NstateW <= Write12;
when Write12 =>
AX_Write_Ready <= '0';
nIOWR <= '1';
NStateW <= Write13;
when Write13 =>
AX_Write_Ready<= '0';
nIOWR <= '1';
NStateW <= Write0;
end case;
end process;
 
J

Jeroen

Michel Bieleveld said:
Yes I have a clock available and processes that i use to synchronize
the state machines, like (in short):

If Reset then CState <= Boot1;
If Clk get high then Cstate <= NState;

The frequency that i am targetting for at the moment is 80 MHz, I
don`t know if it will be reasonable but I hope it is. That is why i
wait 5 clocks (states) for the 60ns to let /IOWR low, and then 100ns ,
8 clocks(states) to make /IOWR high.

I agree about the asynchronous, so that is why i think i solved the
problem by using one combinatorial process, and one synchronizing
process for a state machine. This way it seems too me to garantee
synchronized state machines.

How can i reduce the very long sequence of when => in the following
code ?

I appreciate the help I get from all of you :)

With regards,

Michel.

Best way is to use a counter or shiftregister; and use default assignments
for the outputs. That will make the state machine look much tidier. By using
a counter you can change the timing without messing with the states.
 
J

Jonathan Bromley

I am communicating with another chip. To setup the other chip I need
to make a reset signal of 20ms and then set some registers.
For the communication I need to make a /IOWR pin low for 60ns and high
for at least 100ns. My result were the two main processes listed in my
previous post.
I have no idea to make it more beautiful and would love to hear some
suggestions of how my betters are doing this :)

This is quite a common problem, and as you have already discovered,
the solution as a classic state machine is likely to be ugly.

Other advice you've received is sound and well worth considering,
but there's another possible approach that may be interesting.
Even for such a simple problem as this, I would consider using
some kind of programmable processor. It can be incredibly simple:
the instructions could be as crude as

DRIVE_RESET:
needs "time" argument (number of clocks to assert reset)
WRITE_REG:
needs "address" and "data" arguments
STOP:
asserts a signal that says "done" to the
rest of the system

Now you implement a state machine that:
- reads an opcode word from a memory block (a little on-chip ROM)
- performs the instruction, feeding argument values into the
right bits of hardware at the right time
- increments an opcode word pointer ready for the next fetch

If you're targeting an FPGA, the vendors offer tiny CPU cores
that are well-suited for exactly this kind of thing. But for
your example, it's easy enough to do from scratch. Of course,
it burns up a little extra hardware - but the improved structure
of your design is probably well worth it. For example, if you
need to change the sequence of register writes to suit a slightly
different version of the external chip (or to fix a bug - surely
not :) ) you need only change the ROM contents - the state
mahine design is untouched. Your "procedures" model is
effectively implemented by the tiny processor.

Designing competent CPUs for good performance is really hard.
But designing a little programmable sequence controller,
with no special performance requirements, is rather simple.
For example, if it makes things simpler to add an idle cycle
between fetching the instruction and starting to execute it,
then go ahead and add that idle cycle. After all, this is
being done to set up control registers - it happens very
infrequently, so performance isn't an issue.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL, Verilog, SystemC, Perl, Tcl/Tk, Verification, Project Services

Doulos Ltd. Church Hatch, 22 Market Place, Ringwood, BH24 1AW, UK
Tel: +44 (0)1425 471223 mail:[email protected]
Fax: +44 (0)1425 471573 Web: http://www.doulos.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
M

Mike Treseler

Jeroen said:
Best way is to use a counter or shiftregister; and use default assignments
for the outputs. That will make the state machine look much tidier. By
using a counter you can change the timing without messing with the states.

I agree with Jeroen. There is no reason to limit yourself to
a single process variable. Updating a counter or shifter variable can
be a single line of code replacing a large case statement.
A single-process controller will be a bit tidier than two processes.
Sometimes a couple of booleans is cleaner than a type enumeration.
Try it and see.

-- Mike Treseler
 
M

Michel Bieleveld

Hi Jonathan and all others,

Thanks for helping out ! I will start by using microcode to control
the signals, especially since I will need to do a lot more stuff when
I got the initialization working. And it will be much more easier to
add functionality by adding some "program routines" then to add a lot
of states in a impossible to comprehend state machine. Thanks for all
the inputs !

With regards,

Michel.
 
M

Michel Bieleveld

By the way one more question, does anyone know if I need to specify
every output signal that i want to use in every state. Or does the
xilinx compiler maintain the state of the signals between different
states as long as I don`t change them.

E.g.

when State1 =>
a <= '1';
when State2 =>

Is the value of a in State2 guaranteed '1' or does the compiler
interpret this as a don`t care for a in state2. If so is there
somewhere an option to turn this don`t care interpretation off ?

Michel.
 
J

Jeroen

Michel Bieleveld said:
By the way one more question, does anyone know if I need to specify
every output signal that i want to use in every state. Or does the
xilinx compiler maintain the state of the signals between different
states as long as I don`t change them.

E.g.

when State1 =>
a <= '1';
when State2 =>

Is the value of a in State2 guaranteed '1' or does the compiler
interpret this as a don`t care for a in state2. If so is there
somewhere an option to turn this don`t care interpretation off ?

Michel.

This has to do with VHDL, not the synthesizer. A signal will retain its
value if it's not reassigned a value when the process is iterated again. The
synthesizer will either infer a latch or flipflop, depending if your process
is clocked or not.

I suggest that you better read an (online) VHDL tutorial; there are plenty
and these very basic VHDL issues are covered in there.

Jeroen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top