![]() |
|
ADSP 21xx
Have you found this site useful? Did we save you time? Did we cure your head-ache? Is your hair growing back now? Please make a donation to help with maintenance. |
Objective Real-Time Software on the ADSP21XXLookup Tables and the ADSP 21XXGeneralIn order to handle objects effectively, one needs a clear understanding of the Data Address Generator file and the do until loop mechanism. These constructs provide a way to handle lookup tables and perform register indirect jumps, to do such neat things as finite state machines inside multiple identical objects. Loop RestrictionsWhen coding counted loops, the following restrictions should be borne in mind.
Therefore, if time is not critical, always follow the loop until label with a nop. When speed is of the essence, you can put an instruction in there, provided that it is not a call. Nested loops are best explained by having a look at example 1.
Data Address GeneratorsThe 21XX family has two data address register files. Each file has a set of four registers which allow linear or circular addressing of arrays. The DAGs have a few limitations that one needs to be aware of.
Therefore, use DAG1 for table lookups and DAG2 for register indirect jumps.
Each DAG is a set of registers that are used in combination. The i-register contains the address. The m-register contains the modifier that will be added to the i-register AFTER the access had taken place. The l-register contains the length of a circular buffer. Ensure that the relevant l-register is zero, for linear addressing. A typical indirect access instruction looks like this: ar = dm(i1, m1); This instruction will move the data pointed to by the i1, to the accumulator ar, after which i1 will be post modified by m1, in anticipation of the next access. While it is possible to mix and match i and m-registers, this should be avoided, simply because it is confusing, which can cause bugs. Handling Multiple ObjectsMultiple objects can be handled by a loop, which will cause the same code to be executed repeatedly, to service each object in turn. Typically, a system will have a bunch of common stuff to perform after which it has to service a set of identical objects, such as four audio CODECs. This can be performed in a simple scheduling loop. Assume that the System States module (STA) performs the main scheduling loop, as shown in example 2 below.
Note that we keep the object counter in m1. We'll talk more about that later. Table LookupsIf we save the object instance number in ax1, then a lookup of an object variable can be performed as indicated in example 3 below.
This example will work, but it is not very optimal. Alternatively, we can use the post modify function of the DAGs to our advantage for a 25% speedup on the above example. If we keep the object instance in a modify register m1, the lookup code can simplify a little.
This is the way to handle objective code. It is not as efficient as simply addressing a bunch of named variables, but the advantage is that you need only debug one piece of code, instead of multiple copies thereof.
As you would be using this table lookup function a lot, it is a good candidate to turn into a macro, as shown in example 5.
Now that this macro is defined, you need never worry about how table lookups work anymore. In objective code, this macro will be used very often, for every variable that you want to read from an array. Clearly, you also need a reverse thereof, that will save a variable in an array.
Finite State MachinesA finite state machine is a construct that can be in only one state at any one time. Furthermore, all the possible states and events are pre-defined, which ensures that all possible actions of the machine are known. This ensures deterministic behaviour, which is essential in any real-time system. Finite state machines are easy to debug, since while they can perform the wrong action, they cannot perform anything that is totally unexpected. Even a complex finite state machine usually works reasonably well the very first time around, which is unusual for any piece of software.
Register indirect jumps are useful for the operation of table driven finite state machines. Unfortunately the 21XX cannot perform a register indirect call, which would have been neater, but we can construct a good finite state machine using a jump table.
Assume that we have a finite state machine with four events that need to be handled. This is an example of actions that can be performed through a maintenance port on a system. Assume that the finite state machine is part of a module called Menu (MNU).
This is a very simple finite state machine, having only four events and only one state (Or four states with one event per state, depending on how you want to interpret it). The neat thing is that a state machine such as this, can be used by many objects, just keep the object number in m1. A machine with multiple states and events and a multi dimensional lookup table, is best avoided. The processor architecture makes one dimensional arrays easy to handle, therefore one should stick to it, in the interest of speed. Anything requiring a multi dimensional table, can also be done with a one dimensional table. After all, all of memory is a one dimensional table!
An important thing is to keep the flow of the program neat and tidy. Although the state machine operates with a jump to the event handler, ensure that all handlers will return to the next line at mnu_continue, just as if it was a call to a procedure. This will ensure that the code remains easy to read and understand. Since all your finite state machines are likely going to be of the one dimensional kind as above, you can turn this little critter into a macro too, as described in example 8.
Wow, now we can write object oriented finite state machines. Wheeee! Note that it may be wise to add a range check on the event number in ar, since a bad lookup will result in very weird and wonderful behaviour! Complex Finite State MachinesIn a complex finite state machine, every event handler can be made to return a next event in m4, which will allow the machine to loop on itself until the next event is set to a value that is out of range, indicating that the job is done. An example where this feature can be handy, is the processing of a serial protocol. If the first event idicates that a bit was received, the receiver handler may find that it was the last bit of a message, which means that the CRC needs to be tested, so it then returns a CRC event, to cause the CRC handler to be activated. The CRC handler may reject or accept the message, causing something else to happen.
This loopback method ensures that every event is handled by a short and simple event handler, which is easy to test in isolation. The whole machine can be readily tested by injecting events into the event number m4 and one would need only a single breakpoint, to see what happened and what it is going to do next. This easy test capability is probably the main reason for the popularity of finite state machines. |
|
Copyright © 1996-2008, Aerospace Software Ltd., GPL. |