C way to daisychain interrupts

C and PASCAL (or any other high-level languages) in here please

Moderators: simonsunnyboy, Mug UK, Zorro 2, Moderator Team

User avatar
simonsunnyboy
Moderator
Moderator
Posts: 5101
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

C way to daisychain interrupts

Postby simonsunnyboy » Sun Oct 12, 2014 7:44 am

I often save old interrupt vectors, hookup my own routine and jump to the old routine at the end.

In assembly language, I basically push the old routine's address on the stack and to rts afterwards.

What is a portable C equivalent? The vectors themselves can be read and set with Setexc() from the BIOS. Is there a way to avoid inline assembly?
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee

User avatar
dml
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 3474
Joined: Sat Jun 30, 2012 9:33 am

Re: C way to daisychain interrupts

Postby dml » Sun Oct 12, 2014 9:24 am

simonsunnyboy wrote:I often save old interrupt vectors, hookup my own routine and jump to the old routine at the end.

In assembly language, I basically push the old routine's address on the stack and to rts afterwards.

What is a portable C equivalent? The vectors themselves can be read and set with Setexc() from the BIOS. Is there a way to avoid inline assembly?


There is no portable C equivalent.

There are some ways you can do this from C, but they all involve either assembly syntax embedded in the C, or intrinsics / compiler extensions which provide access to stuff C doesn't permit (like the stack, or emitting special opcodes).

You might be able to achieve something similar through system functionality (TOS) but it will depend on the interrupt, scenario and what you mean by 'portable'.

User avatar
simonsunnyboy
Moderator
Moderator
Posts: 5101
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: C way to daisychain interrupts

Postby simonsunnyboy » Sun Oct 12, 2014 9:49 am

Portable in this case means "compiles correctly on different C compilers without rewrite for the Atari platform"

But I fear I got the problem....I had hoped there was a special way of function pointer syntax to use. It mainly is of concern for Timer C, in the VBL I can count the important system variables by hand but I am lost what Timer C can do, esp with harddisk drivers in place, thus I prefer to leave the old functionality in place.

In that case, I'm probably best off with sticking to some assembly for the case where I need the daisy chaining.
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee

User avatar
dml
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 3474
Joined: Sat Jun 30, 2012 9:33 am

Re: C way to daisychain interrupts

Postby dml » Sun Oct 12, 2014 9:55 am

simonsunnyboy wrote:Portable in this case means "compiles correctly on different C compilers without rewrite for the Atari platform"

But I fear I got the problem....I had hoped there was a special way of function pointer syntax to use. It mainly is of concern for Timer C, in the VBL I can count the important system variables by hand but I am lost what Timer C can do, esp with harddisk drivers in place, thus I prefer to leave the old functionality in place.

In that case, I'm probably best off with sticking to some assembly for the case where I need the daisy chaining.


IIRC with TimerC you need to increment some TOS counters in the $4xx area but otherwise it can be replaced without daisychaining, and with HD drivers still behaving.

If you don't advance the counters disk access can halt.

Some TOS interrupts however provide callbacks so you can attach a C function to them and TOS will call your code. This is the cleanest way to hook things but it is only provided for some TOS services.

User avatar
simonsunnyboy
Moderator
Moderator
Posts: 5101
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: C way to daisychain interrupts

Postby simonsunnyboy » Sun Oct 12, 2014 12:01 pm

According to my old Atari ST Profibuch (1988 edition), only the 200hz counter is increased, something I could do by hand.

At a 50Hz rate it processes Dosound(), does key repeat and then comes something interesting:

"jump through etv_timer with _timer_ms as parameter on stack"

Sadly there is no further documentation what is hooked into this callback and no information if it is terminated by rts or rte.
It could be interesting for clean 50hz timings, but I use Timer C to synthesize a custom call rate (for SNDH replay)
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee

User avatar
dml
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 3474
Joined: Sat Jun 30, 2012 9:33 am

Re: C way to daisychain interrupts

Postby dml » Sun Oct 12, 2014 1:47 pm

simonsunnyboy wrote:"jump through etv_timer with _timer_ms as parameter on stack"

Sadly there is no further documentation what is hooked into this callback and no information if it is terminated by rts or rte.
It could be interesting for clean 50hz timings, but I use Timer C to synthesize a custom call rate (for SNDH replay)


See the description of Setexc() here:

http://www.yardley.cc/atari/compendium/ ... erence.htm

This likely provides the hooking functionality you're after, via exc_timer.

I'm sure the termination procedure for the new vector is documented somewhere else.

User avatar
shoggoth
Nature
Nature
Posts: 971
Joined: Tue Aug 01, 2006 9:21 am
Location: Halmstad, Sweden
Contact:

Re: C way to daisychain interrupts

Postby shoggoth » Sun Oct 12, 2014 2:13 pm

Just be nice and use XBRA.
Ain't no space like PeP-space.

User avatar
simonsunnyboy
Moderator
Moderator
Posts: 5101
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: C way to daisychain interrupts

Postby simonsunnyboy » Mon Oct 13, 2014 3:17 pm

shoggoth wrote:Just be nice and use XBRA.


I can do so, but anyone intercepting and redirecting interrupts from a running game or demo is either a very good debugger or a hacker or both xD

It still won't solve my problem how to cleanly push the old address on the stack.
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee

mc6809e
Captain Atari
Captain Atari
Posts: 159
Joined: Sun Jan 29, 2012 10:22 pm

Re: C way to daisychain interrupts

Postby mc6809e » Mon Oct 13, 2014 5:45 pm

If you're using gcc you might be able to use a computed goto.

Save the old address in a void * and then when you've reached the end of your handler, do something like goto *old to transfer control to the old handler.

User avatar
shoggoth
Nature
Nature
Posts: 971
Joined: Tue Aug 01, 2006 9:21 am
Location: Halmstad, Sweden
Contact:

Re: C way to daisychain interrupts

Postby shoggoth » Tue Oct 14, 2014 6:03 am

mc6809e wrote:If you're using gcc you might be able to use a computed goto.

Save the old address in a void * and then when you've reached the end of your handler, do something like goto *old to transfer control to the old handler.


I wouldn't attempt that; goto outside the current function is undefined. Might "work", but then again it's not guaranteed to do so, and in such case it sure ain't prettier than a few lines of assembly code..
Ain't no space like PeP-space.

mc6809e
Captain Atari
Captain Atari
Posts: 159
Joined: Sun Jan 29, 2012 10:22 pm

Re: C way to daisychain interrupts

Postby mc6809e » Tue Oct 14, 2014 10:19 am

shoggoth wrote:I wouldn't attempt that; goto outside the current function is undefined. Might "work", but then again it's not guaranteed to do so, and in such case it sure ain't prettier than a few lines of assembly code..


That depends on who is doing the defining!

You're correct if you mean that computed gotos are not an official part of C, but the GCC developers have included the feature in the language so it's defined by the GCC developers for their particular compiler.

deeez
Atari User
Atari User
Posts: 41
Joined: Fri May 03, 2013 4:51 pm

Re: C way to daisychain interrupts

Postby deeez » Tue Oct 14, 2014 2:10 pm

OP said portable C in his first post so I guess we can't assume gcc :)

User avatar
shoggoth
Nature
Nature
Posts: 971
Joined: Tue Aug 01, 2006 9:21 am
Location: Halmstad, Sweden
Contact:

Re: C way to daisychain interrupts

Postby shoggoth » Tue Oct 14, 2014 4:09 pm

mc6809e wrote:You're correct if you mean that computed gotos are not an official part of C, but the GCC developers have included the feature in the language so it's defined by the GCC developers for their particular compiler.


Yep. And the GCC manual states that the results of jumping outside of the current function is undefined - hence a bad idea. I know about this feature since I use it extensively in my current project.
Ain't no space like PeP-space.

User avatar
simonsunnyboy
Moderator
Moderator
Posts: 5101
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: C way to daisychain interrupts

Postby simonsunnyboy » Tue Oct 14, 2014 4:37 pm

deeez wrote:OP said portable C in his first post so I guess we can't assume gcc :)


Well spotted although gcc wil be prime suspect for trying.

I think I will fall back to provide it in assembly language and link a toolchain dependant source. In the end it is probably clearer and easier to read. No goto in my C sources allowed ;)
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee

mc6809e
Captain Atari
Captain Atari
Posts: 159
Joined: Sun Jan 29, 2012 10:22 pm

Re: C way to daisychain interrupts

Postby mc6809e » Tue Oct 14, 2014 6:25 pm

shoggoth wrote:
mc6809e wrote:You're correct if you mean that computed gotos are not an official part of C, but the GCC developers have included the feature in the language so it's defined by the GCC developers for their particular compiler.


Yep. And the GCC manual states that the results of jumping outside of the current function is undefined - hence a bad idea. I know about this feature since I use it extensively in my current project.


Few C programs of any size and usefulness lack undefined behavior, especially when working at the machine level.

The C standard even acknowledges this to some extent by having invented a class of "implementation defined" operations. What happens when a uint32_t is right shifted by 33 bits, for example? On x86 platforms x>>=33 == x>>1 where x is uint_32 because shift amounts are masked to 5-bit values before the shift, just like on the processor. On 68K, though, x>>=33 equals 0 as most expect.

What to do? Leave right unsigned shifts undefined? Too much code has been written that uses right shifts. Should one definition be used, thus crippling one of the processors and forcing the compiler to use extra operations to make one processor look like another with respect to shifts? What about legacy code that depends on shifts being masked on x86 platforms? Break it?

Thus the invention of "implementation defined".

On the other hand right shifts on signed values are undefined. The compiler might decide that -4>>2 equals 4393.

C doesn't even guarantee that a char is 8 bits. Your code might run on a PDP-10 with its 9 bit byte, right?

Let's be reasonable. This is code meant to run on a particular architecture.

If it were me, I'd try the computed goto method, looking at the generated machine code, and watch that nothing in the interrupt handler touches the stack. That means obviously it can't use local variables and it can't call other functions.

If the compiled code is linear, doesn't touch the stack, and transfers control to the old handler at the end (with a jmp (ax) or similar), then the code should work.

User avatar
Eero Tamminen
Atari God
Atari God
Posts: 1956
Joined: Sun Jul 31, 2011 1:11 pm

Re: C way to daisychain interrupts

Postby Eero Tamminen » Tue Oct 14, 2014 9:42 pm

My advice, for what it's worth: don't use non-standard corner-case compiler features on corner-case HW platforms (or even more popular ones). They break from one compiler version to another when you have optimizations enabled (example: anonymous/nested functions on ARM).

User avatar
shoggoth
Nature
Nature
Posts: 971
Joined: Tue Aug 01, 2006 9:21 am
Location: Halmstad, Sweden
Contact:

Re: C way to daisychain interrupts

Postby shoggoth » Thu Oct 16, 2014 4:50 am

mc6809e wrote:
shoggoth wrote:
mc6809e wrote:You're correct if you mean that computed gotos are not an official part of C, but the GCC developers have included the feature in the language so it's defined by the GCC developers for their particular compiler.


Yep. And the GCC manual states that the results of jumping outside of the current function is undefined - hence a bad idea. I know about this feature since I use it extensively in my current project.


Let's be reasonable. This is code meant to run on a particular architecture.

If it were me, I'd try the computed goto method, looking at the generated machine code, and watch that nothing in the interrupt handler touches the stack. That means obviously it can't use local variables and it can't call other functions.


Whatever floats your boat, but personally I think such practice should be the subject of a public beating or at least a light kick in the nut sack. The result isn't guaranteed to stay the same across optimization levels or compiler revisions, It doesn't add clarity or portability, and any future problems are obfuscated since the compiler is likely to accept the code even though it's inherently broken. The alternative - a very few lines of assembly code - may not be portable across different compilers, but then again you're likely to get error messages instead of a broken binary.
Ain't no space like PeP-space.

User avatar
mfro
Atari Super Hero
Atari Super Hero
Posts: 802
Joined: Thu Aug 02, 2012 10:33 am
Location: SW Germany

Re: C way to daisychain interrupts

Postby mfro » Thu Oct 16, 2014 6:58 am

+1

Go with a few lines of (inline-) assembly and - although its not portable - its clear to everyone (including yourself) what you are doing.

About the closest you can probably get with standard C would be to tweak longjmp() to suit your problem. Although it's standard, it won't be portable since you would probably need to fiddle with the jmp_buf which you are explicitely not allowed to. So it's just an idea, not necessarily a good one...

User avatar
simonsunnyboy
Moderator
Moderator
Posts: 5101
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: C way to daisychain interrupts

Postby simonsunnyboy » Thu Oct 16, 2014 3:54 pm

"light kick in the nut sack" -> make that a heavy one ;)

I think a dedicated part of toolchain dependant assembly language code is still more readable than setjmp or goto in C. I'll head that way and for me the case is closed.
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee

User avatar
Arne
Atari Super Hero
Atari Super Hero
Posts: 512
Joined: Thu Nov 01, 2007 10:01 am

Re: C way to daisychain interrupts

Postby Arne » Mon Feb 09, 2015 11:01 am

simonsunnyboy wrote:In assembly language, I basically push the old routine's address on the stack and to rts afterwards.

What is a portable C equivalent?


So the difficulty is to jump - using only C - to a given address?

Pretty easy then I would say:

Code: Select all

#define IOREAD(ADDR,SIZE)               (*((volatile uint ## SIZE ## _t*)(ADDR)))
#define IOWRITE(ADDR,SIZE,DATA)            (*((volatile uint ## SIZE ## _t*)(ADDR)) = (DATA))

typedef void (*pFunction)(void);
pFunction   JumpToHandler;
uint32_t   JumpAddress;

JumpAddress = (*(volatile uint32_t*) (IOREAD(OldHandler, 32));
JumpToHandler = (pFunction) JumpAddress;
JumpToHandler();


Code: Select all

(IOREAD(OldHandler, 32))

shall return the address where you want to jump to.

I use this code on an embedded platform (STM32) to do a jump from my bootloader to the start of the application. Bootloader and application are compiled and linked as stand-alone pieces of code. They use different linker scripts for the different address-ranges in Flash memory they use.
Runs smootly... for some years now... on a couple of thousand machines... every day. :D

User avatar
shoggoth
Nature
Nature
Posts: 971
Joined: Tue Aug 01, 2006 9:21 am
Location: Halmstad, Sweden
Contact:

Re: C way to daisychain interrupts

Postby shoggoth » Mon Feb 09, 2015 1:43 pm

Arne wrote:So the difficulty is to jump - using only C - to a given address?


Not really - the difficulty is to instruct the compiler to return using RTE, and to save/restore all registers etc. For some reason, there's no pragma/intrinsic for this in our GCC port, but perhaps there is such a thing in VBCC.

The almost portable way would be a small assembly wrapper, and often you need to do that anyway for software interrupts. Even though assembly syntax differs somewhat, it's fairly simple to move from one environment to another.
Ain't no space like PeP-space.

User avatar
Arne
Atari Super Hero
Atari Super Hero
Posts: 512
Joined: Thu Nov 01, 2007 10:01 am

Re: C way to daisychain interrupts

Postby Arne » Mon Feb 09, 2015 2:11 pm

shoggoth wrote:Not really - the difficulty is to instruct the compiler to return using RTE, and to save/restore all registers etc.

In his 1st post ssb wrote he pushes the next handler's address onto the stack and calls RTS - not RTE.
Isn't it satisfactory if the last handler in the chain does the RTE?

User avatar
mfro
Atari Super Hero
Atari Super Hero
Posts: 802
Joined: Thu Aug 02, 2012 10:33 am
Location: SW Germany

Re: C way to daisychain interrupts

Postby mfro » Mon Feb 09, 2015 2:19 pm

shoggoth wrote:Not really - the difficulty is to instruct the compiler to return using RTE, and to save/restore all registers etc. For some reason, there's no pragma/intrinsic for this in our GCC port,

Actually

Code: Select all

__attribute__((interrupt))


attached to a function forces gcc to return with an rte instruction. This won't help you much, however, since gcc doesn't apply a suitable prolog/epilog where it saves/restores registers.

User avatar
simonsunnyboy
Moderator
Moderator
Posts: 5101
Joined: Wed Oct 23, 2002 4:36 pm
Location: Friedrichshafen, Germany
Contact:

Re: C way to daisychain interrupts

Postby simonsunnyboy » Mon Feb 09, 2015 4:22 pm

Arne wrote:
simonsunnyboy wrote:In assembly language, I basically push the old routine's address on the stack and to rts afterwards.

What is a portable C equivalent?


So the difficulty is to jump - using only C - to a given address?

Pretty easy then I would say:

Code: Select all

#define IOREAD(ADDR,SIZE)               (*((volatile uint ## SIZE ## _t*)(ADDR)))
#define IOWRITE(ADDR,SIZE,DATA)            (*((volatile uint ## SIZE ## _t*)(ADDR)) = (DATA))

typedef void (*pFunction)(void);
pFunction   JumpToHandler;
uint32_t   JumpAddress;

JumpAddress = (*(volatile uint32_t*) (IOREAD(OldHandler, 32));
JumpToHandler = (pFunction) JumpAddress;
JumpToHandler();


Code: Select all

(IOREAD(OldHandler, 32))

shall return the address where you want to jump to.

I use this code on an embedded platform (STM32) to do a jump from my bootloader to the start of the application. Bootloader and application are compiled and linked as stand-alone pieces of code. They use different linker scripts for the different address-ranges in Flash memory they use.
Runs smootly... for some years now... on a couple of thousand machines... every day. :D


If this correctly optimizes to a jump it is exactly what I was looking for :) It basically makes use of a function call being last before the return statement is automatically optimized into a jump statement?

The bootloaders at my company use a similar construct but in a bootloader useless rts etc are not so much of a waste.
Simon Sunnyboy/Paradize - http://paradize.atari.org/

Stay cool, stay Atari!

1x2600jr, 1x1040STFm, 1x1040STE 4MB+TOS2.06+SatanDisk, 1xF030 14MB+FPU+NetUS-Bee

User avatar
mfro
Atari Super Hero
Atari Super Hero
Posts: 802
Joined: Thu Aug 02, 2012 10:33 am
Location: SW Germany

Re: C way to daisychain interrupts

Postby mfro » Mon Feb 09, 2015 5:51 pm

simonsunnyboy wrote:If this correctly optimizes to a jump it is exactly what I was looking for :) It basically makes use of a function call being last before the return statement is automatically optimized into a jump statement?

I don't think so. I'd say this could only be safely done if the call gets inlined (may be if it's statically defined but I'd be not to sure about that). Otherwise gcc can't be sure that the said function won't be called from elsewhere.


Social Media

     

Return to “C / PASCAL etc.”

Who is online

Users browsing this forum: Raibearth and 1 guest