I have noticed that the Kiel compiler doesn't produce the correct interrupt vector if 8051 interrupt numbers are used. For example for external interrupt 0 (IE0), the interrupt number has to be 0, instead of 1 to produce a jump at location 1. Example:
void edge1 (void) interrupt 0{ /*produces correct code
while
void edge1 (void) interrupt 1{ /*produces wrong code
This is the case with all the interrupts I have used. My questions is what do you have to do to produce a reset vector? Reset is interrupt number 0 in 8051 numbering. Using -1 or 255 both produce a compile error.
I don't understand why precise definitions are needed when different manufacturers use different terminology. Some call interrupts and RESET an exception. Others classify RESET as an NMI. The only thing I'm concerned with is that if Keil had used the same numbering scheme as the chip manufacturers (RESET = 0, int0 = 1, etc) your code would be capable of producing a RESET vector.
what do you want a reset vector for???
a jmp 0 would do the same since no return would be possible
Erik
I don't understand why precise definitions are needed when different manufacturers use different terminology.
I'd say this entire thread is an example of why we not only need precise definitions but we need people to use them.
The only thing I'm concerned with is that if Keil had used the same numbering scheme as the chip manufacturers (RESET = 0, int0 = 1, etc) your code would be capable of producing a RESET vector.
The question remains, however, as to what one could possibly want to achieve (in the context of a C program) by "producing a reset vector". I am assuming that by this you mean using the 'interrupt' function qualifier to either place the function code at location zero or place a jump to the function at location zero?
Note also that the reset vector would have to be treated as a special case by the compiler as reset does not cause a return address to be pushed onto the stack unlike a, dare I say it, real interrupt.
"The only thing I'm concerned with is that if Keil had used the same numbering scheme as the chip manufacturers "
But we've clearly establsihed that there is no universal numbering scheme for 8051 interrupts!
Keil clearly, explicitly, and unambiguously define the meaning of the number to be used with their specific keyword extension - there is no claim that it relates to any other numbering scheme that anyone else may or may not associate with 8051 interrupts.
"code would be capable of producing a RESET vector."
No, it wouldn't. because Keil's interrupt keyword is about specifying a function to be an interrupt handler - by modifying its preamble and "post-amble". You don't want to do that for a Reset "Handler", do you?
You still haven't said what you are actually trying to achieve here!
Note that Tasking uses the same numbering scheme as Keil...
And so does SDCC: sdcc.sourceforge.net/.../node69.html
As the guy who wrote all that Keil documentation, I think it's necessary to point a few things out:
"...The form of an INTERRUPT attribute is:
INTERRUPT n
with an optional USING attribute, where n is a number. Each number can only be used once in a program. Each such procedure is then referred to as an interrupt procedure.
Each MCS-51 interrupt can he individually enabled or disabled (the 8051 has five: Ext 0 (0). Timer 0 (1), Ext 1 (2). Timer 1 (3). and Serial Int (4): other members of the family may have more or less)."</p>
So, as you can clearly see, it is Intel's fault. :-)
Allowing the reset vector as interrupt 0 would have strange consequences:
Therefore, the reset vector is handled like I've seen it handled on practically every other HLL system. It's special and it's handled in the startup code.
Hope this helps.
Jon
Indeed.
I guess the exception (sic?) to this is the Cortex-M chips - which have been specifically designed so that the vectors (interrupt, exception, and reset) can be coded in 'C'?
If the OP really wants to pogram a reset vector in 'C', perhaps he should look at a Cortex-M chip instead...?
Having said that, Keil still provide their startup code in assembler with their Cortex-M tools...
As the guy who wrote all that Keil documentation
You have my sympathy. Excellent job, though.
With a bit of luck that puts an end to the majority of this thread, although I have to confess I remain curious as to what the OP was trying to achieve.
A very optimistic attempt at persistent state?
After a power on let the reset handler have the processor return to the previous execution point with retained variable and register states?
Well, the 8051 architecture was their invention - so I guess they are (or, at least, were) entitled to do whatever they like with it!
although I have to confess I remain curious as to what the OP was trying to achieve.
I agree with Jack
Excellent job again, I agree with Jack
My guess is that the OP coded something without reading the 'background' (Interrupt_vector_address - 3)/8) before typing interrupt numbers in some code and got upset that Keil did not agree with his assumptions
He clearly has some fixed notion about "interrupt numbers" and is not prepared to accept that it does not match Keil's notion of "interrupt numbers" as implemnented in their C51 product
I have been using and writing interrupt-driven software for almost 35 years and have learned that if you can think outside of the box, and be more creative, you can be come up with more interesting ways of doing things. Several years ago my faculty adviser showed me a paper he wrote describing a computer instruction set. In those days most (mini) computer instruction sets had an indirect bit. After glancing through his paper I noticed his proposed architecture had no indirect bit and mentioned that. His response was "Current thinking is that an indirect bit isn't needed". My co-workers at Digilab (an FTIR spectrometer manufacturer) laughed at that. But Ron Rivest's next paper on a novel cryptographic system was better received. Here's how I would like to use interrupt keyword in the Keil 8051 compiler if it included RESET: extern void my_reset (void) interrupt 0 {} // emits an LJMP
This puts a long jump at address 0 to the external function my_reset. My_reset is an assembly language startup routine. It exits with a long jump to the user's Main (start of C code). This allows a programmer to write their own C_Start. I imagine you could do the same thing with interrupts, but the programmer would have to end their function body with an RTI.
But it doesn't really give any true advantage, compared to writing a "normal" startup file in assembler. The end result is still a need to either have the end user write startup code in assembler, or have the end user accept a standard startup file.
ARM did think outside the box, when they designed the Cortext to allow everything to be written in C. The vector table contans the address of the startup function (in C), and the startup address and size of the stack. And there is no need for any special keyword for interrupt handlers, since the core handles the entry/exit magic and calls a standard C function.
True, it looks like 6 of one or half a dozen of another at first glance. To create a different startup file now you have to modify STARTUP.A51 or create a similar startup program. When your program is compiled a long jump to the entry point of STARTUP is placed at address 0. What I propose would still require writing an assembly language startup function. But the extern could also be an address in the processor's monitor space. While you can still do that with 2 long jumps by placing the extern in STARTUP.A51, that is not even crufty. The other reason for having RESET in the name space of the C program is to allow a soft restart of the program (without using the watchdog). Others have stated this is impossible, illegal or illogical because of stack issues but that isn't true. STARTUP initializes the stack pointer, etc then jumps to MAIN. C has traditionally been a language that lets the programmer do whatever he/she wants. Although not everyone agrees with that.
The problem with jumping for soft-start isn't just the stack. The problem is that the processor hasn't been reset so all peripherials can still be initialized and running.
STARTUP may initialize the stack but your first interrupt may happen before the stack has been initialized. Before jumping to the startup code, the application must - at least - disable interrupts. And the startup code (and everything from main() and forward) may also assume that it is a "normal" startup, where all peripherials have their boot-state defaults. Enabling interrupts globally without initializing the UART device may directly trig an interrupt for handling characters received since before the reboot.
It is normally better to have a processor with a watchdog and let the watchdog reset the processor. A check for reboot reason and memory state could then let the startup code decide if all memory should be cleared/initialized, or if it was an intentional watchdog reset with the intention to keep some state.