src@mssx.UUCP (Pleschutznig Andreas) (08/29/88)
Suppose following:
We want to write a software emulation for another processor on UNIX
So the main problem is to get into the emulation routines as fast as possible,
and therefore it doe not seem to be good enough to do
switch (code) {
case ..
case ..
}
So we thought of doing that job by declaring the addresses of the emulation
routines and jumping to the routines by address like this
(*addressarray[code]);
I know, I know that *does not* work, but maybe there is someone knowing to
get around.
noren@dinl.uucp (Charles Noren) (08/31/88)
I'm not sure if I understand, but try something like this: typedef void (*func)() funcarray; void func1(), func2(), func3(),... /* Function Prototypes */ funcarray addressarray [] = { func1, func2, func3,... } ...and then execute this function to call function by address code: void execute (array, code) funcarray array[]; int code; { void (*function) (); function = array[code]; (*function)(); } ...the calling code would look like: execute (addressarray, code); I have not tried this, but I have used something very similar for implementing finite state machines using state/event matrices and it worked quite well. chuck
djones@megatest.UUCP (Dave Jones) (08/31/88)
From article <679@mssx.UUCP>, by src@mssx.UUCP (Pleschutznig Andreas): ... > > So we thought of doing that job by declaring the addresses of the emulation > routines and jumping to the routines by address like this > > (*addressarray[code]); > > I know, I know that *does not* work, but maybe there is someone knowing to > get around. Nothing to "get around". There is nothing in your way. You just left off the empty parameter list (). (First language Pascal?) /* declaration */ int routine1(), routine2(), routineN(); int (*addressarray[])() = { routine1, routine2, routineN }; /* calling sequence */ int return_value = (*addressarray[code])();
djones@meest.UUCP (Dave Jones) (08/31/88)
From article <679@mssx.UUCP>, by src@mssx.UUCP (Pleschutznig Andreas): ... > > So we thought of doing that job by declaring the addresses of the emulation > routines and jumping to the routines by address like this > > (*addressarray[code]); > > I know, I know that *does not* work, but maybe there is someone knowing to > get around. Nothing to "get around". There is nothing in your way. You just left off the empty parameter list (). (First language Pascal?) /* declaration */ int routine1(), routine2(), routineN(); int (*addressarray[])() = { routine1, routine2, routineN }; /* calling sequence */ int return_value = (*addressarray[code])(); #!
chris@mimsy.UUCP (Chris Torek) (08/31/88)
In article <626@dinl.mmc.UUCP> noren@dinl.uucp (Charles Noren) writes: Your syntax needs work: >typedef void (*func)() funcarray; `typedef void (*func)();' or `typedef void (*funcarray[])()'. >void func1(), func2(), func3(),... /* Function Prototypes */ These are declarations, but not prototype declarations. (There is a substantial difference.) >funcarray addressarray [] = { > func1, func2, func3,... >} If the typedef includes the []s, the declaration should not; conversely, if the typedef does not, the declaration should. This would work given typedef void (*funcarray)(); although I think this is a misleading name (there is no array here). >...and then execute this function to call function by address code: > >void execute (array, code) >funcarray array[]; >int code; >{ > void (*function) (); > > function = array[code]; > (*function)(); >} This syntax is correct. >...the calling code would look like: > > execute (addressarray, code); The multiple levels of calling are unnecessary. If `a' is an object of type `array N of pointer to function (args) returning void', then the syntax to call that function is (*a[i])(args); so the call to `execute(addressarray, code)' can be replaced with `(*addressarray[code])()'. Note that subscript `[]' binds more tightly than indirection `*', so the format (*(a[i]))(args) suggested in another article is also correct. The formats a[i](args) (and, equivalently, (a[i])(args)) are NOT correct by K&R 1st ed., although they have been legitimised in the three draft proposed ANSI standards submitted for public review, and are accepted by numerous compilers. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
bill@proxftl.UUCP (T. William Wells) (08/31/88)
In article <679@mssx.UUCP> src@mssx.UUCP (Pleschutznig Andreas) writes:
: Suppose following:
:
: We want to write a software emulation for another processor on UNIX
:
: So the main problem is to get into the emulation routines as fast as possible,
: and therefore it doe not seem to be good enough to do
:
: switch (code) {
: case ..
: case ..
: }
:
: So we thought of doing that job by declaring the addresses of the emulation
: routines and jumping to the routines by address like this
:
: (*addressarray[code]);
:
: I know, I know that *does not* work, but maybe there is someone knowing to
: get around.
The correct call is
(*addressarray[code])();
However, you will probably find the switch to be faster.
----
The following analysis presumes that we are running on something
of the order of a Vax, 386, or 68k, and have a reasonable C
compiler.
Here is what the switch is likely to generate:
move a0,code (written in GASM: Generic Assembler)
cmp a0,256
jgrtr after (branch if *unsigned* greater than 256)
shiftl a0,2
jmp table[a0]
The call should generate something like
move a0,code
shiftl a0,2
call table[a0]
and the function should add to this
sub sp,#locals (or something else to make a stack frame)
...
return
The difference between these is:
move a0,code move a0,code
cmp a0,256 shiftl a0,2
jgrtr after call table[a0]
shiftl a0,2 sub sp,#locals
jmp table[a0] return
On the machines I am familiar with, the cmp and sub instructions
are about equivalent in execution time, so leaving out that and
the common instructions, we have:
jgrtr after call table[a0]
jmp table[a0] return
I would expect that the not-taken branch + the indirect branch to
take significantly less time than the call + return. I also have
been *very* generous in my assumptions about how fast the call
will be; it often will have more overhead than the one
instruction I added.
You could also get rid of the cmp and jgrtr instructions, if you
are *certain* that the code passed will always be within range.
Some compilers let you create assembler output instead of object
output; you take that assembler output, run a sed script on it,
and then assemble that. You can use this method to tweak all
sorts of things, besides. But do this only if you are *really*
desperate for speed.
(I wanna #pragma :-)
---
Bill
novavax!proxftl!bill
ark@alice.UUCP (Andrew Koenig) (09/01/88)
> From article <679@mssx.UUCP>, by src@mssx.UUCP (Pleschutznig Andreas): > So we thought of doing that job by declaring the addresses of the emulation > routines and jumping to the routines by address like this > (*addressarray[code]); Before you travel this route, I suggest you measure the relative time it takes to execute a switch vs. to call a function. You may find that the switch is faster. -- --Andrew Koenig ark@europa.att.com
lai@vedge.UUCP (David Lai) (09/01/88)
In article <679@mssx.UUCP> src@mssx.UUCP (Pleschutznig Andreas) writes: >Suppose following: > >We want to write a software emulation for another processor on UNIX >So we thought of doing that job by declaring the addresses of the emulation >routines and jumping to the routines by address like this > > (*addressarray[code]); > >I know, I know that *does not* work, but maybe there is someone knowing to >get around. You're missing the function call parenthesis: (*addressarray[code])(); the example below works, and is approx what you want to do (besides out news wont let me send the above unless I have more new text): typedef int (*ptr_to_int_returning_func)(); /* declares a type for readability */ extern int printf(), fprintf(), scanf(), strlen(); ptr_to_int_returning_func array_of_func_ptrs[]= { printf, fprintf, scanf, strlen }; /* get the idea? */ main() { /* lets do a few calls */ int i; i = (*array_of_func_ptrs[3])("test_strlen"); (*array_of_func_ptrs[0])("size was %d\n",i); /* test printf */ } I hope the example helps with the nasty syntax. -- "What is a DJ if he can't scratch?" - Uncle Jamms Army The views expressed are those of the author, and not of Visual Edge, nor Usenet. David Lai (vedge!lai@larry.mcrcim.mcgill.edu || ...watmath!onfcanim!vedge!lai) -- "What is a DJ if he can't scratch?" - Uncle Jamms Army The views expressed are those of the author, and not of Visual Edge, nor Usenet. David Lai (vedge!lai@larry.mcrcim.mcgill.edu || ...watmath!onfcanim!vedge!lai)
cdold@starfish.Convergent.COM (Clarence Dold) (09/10/88)
From article <679@mssx.UUCP>, by src@mssx.UUCP (Pleschutznig Andreas): > > So we thought of doing that job by declaring the addresses of the emulation > routines and jumping to the routines by address like this > > (*addressarray[code]); > > I know, I know that *does not* work, but maybe there is someone knowing to > get around. I don't know about that not working, but this one does work. For QuickC, running on a PC, jumps to a ROM based routine (actually the reset jump for an 8088 CPU chip). I use this same method to 'wrap' the ROM based disk format that is contained in BIOS ROM on the controller card with a friendlier menu. main () { void (far *bye) (); int far *pt; pt = ((int far *) (0x0000472L); *pt = 0x1234; /* for warm boot */ /* *pt = 0x0000; */ /* for cold boot */ bye = (void far *) 0x0ffff0000L; (*bye) (); } -- Clarence A Dold - cdold@starfish.Convergent.COM (408) 435-5274 ...pyramid!ctnews!mitisft!professo!dold P.O.Box 6685, San Jose, CA 95150-6685
chris@mimsy.UUCP (Chris Torek) (09/10/88)
In article <707@starfish.Convergent.COM> cdold@starfish.Convergent.COM (Clarence Dold) writes: >... For QuickC, running on a PC, jumps to a ROM based routine (actually the >reset jump for an 8088 CPU chip)... > >main () >{ > void (far *bye) (); > int far *pt; > > pt = ((int far *) (0x0000472L); [missing ) somewhere here] > *pt = 0x1234; /* for warm boot */ > /* *pt = 0x0000; */ /* for cold boot */ > > bye = (void far *) 0x0ffff0000L; > (*bye) (); >} Incidentally, this program can be `simplified' (and from dumb-but-fast compilers, the resulting code probably will be noticeably shorter) to main() { *(int far *)0x472L = 0x1234; /* warm boot */ /* = 0 cold boot */ (*(void (far *)())0xffff0000L)(); } The addresses can (and probably should) be prettied up with `#define's, at least for anything even slightly more substantial than this example. (I confess to being somewhat surprised at the difference between warm and cold boots; more often, a warm boot is done by jumping to some other address than the ROM restart address. Something like #define COLDBOOT ((void (*)())0xfc000000) #define WARMBOOT ((void (*)())0xfc000004) (*(cold ? COLDBOOT : WARMBOOT))(); or if you prefer the readable version :-) , if (cold) (*COLDBOOT)(); else (*WARMBOOT)(); ) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris