Re: [cc65] c64 question

Date view Thread view Subject view

From: Ullrich von Bassewitz (uz_at_musoftware.de)
Date: 2001-03-07 23:28:17


On Wed, Mar 07, 2001 at 10:51:40PM +0000, Arvid Norberg wrote:
> What happens when the 6502 gets an interrupt?
> I've always imagined that the folowing steps are performed by the CPU:
>  1. CPU registers were pushed onto the stack (a, x, y, pc).
>  2. execution jumped to the interrupt handler
>  3. when rti is reached, the resgisters are popped back and execution
> continues where it was interrupted.

Saving registers is not done by the 6502 itself but must be done by the
interrupt routine. The 6502 saves the condition codes (flags) and the return
address.

> I don't see what pushing ints onto the stack has to do with this.
[...]
> This means that I don't understand why the stack get messed up.

Have a look at the following routine. It has the purpose to increment the
stack. I've made it samewhat simpler than the last example (which was the
actual routine minus 65C02 code and was optimized for speed):

incsp:	inc	sp		; Increment low byte
	    			; <-- Assume interrupt here
	bne	@L1		; Jump if no overflow
	inc	sp+1		; Overflow, increment high byte
@L1:	rts

Now assume that the value of the stackpointer is $CBFF. This means that the
low byte will overflow and the high byte has to be incremented, too. The final
value (after calling the function) should be $CC00.

If an interrupt occurs after incrementing the low byte (marked with an arrow),
the value of the stack pointer at this point is $DB00 - which is not only
wrong, but may also be outside the stack area.

Now, if you call a C function, this C function will use the stack, and this
means that it will use an invalid stack pointer. 

The problem here is, that the increment of the stack pointer is not atomic, so
it may have an invalid value if the routine is interrupted.

[Saving registers]
> This, I can understand, is a problem.
> (Not that I know what those register migth contain, especially for a
> void function that takes no parameters).

The zero page locations are the working variables of the C compiler
(comparable to real registers on other CPUs). Not saving these locations would
be equal to not saving registers in an interrupt routine.

> I also think I've found a minor bug in cc65. The following code:
>
> #include <conio.h>
>
> void main(void)
> {
> 	char a = -1;
> 	if (a < 0 || a > 2) cputs("a < 0 or a > 2\n");
> }
>
> generates the following warning, when compiled.
>
> test.c(6): Warning: Condition is never true

The compiler is correct here. Characters are unsigned, so variable a can never
be less than zero. If you want signed characters, you have to declare them
explicitly as such:

	signed char a = -1;
	if (a < 0 || a > 2) cputs("a < 0 or a > 2\n");

This code will not longer produce the warning. Please note however, that
operations on signed data types are usually slower compared to the same
operations on the equivalent unsigned data type, because the 6502 does not
support signed data very good, so the compiler must generate additional code.
For best performance avoid signed data types if you can.

Regards


	Uz


--
Ullrich von Bassewitz                                  uz_at_musoftware.de
----------------------------------------------------------------------
To unsubscribe from the list send mail to majordomo_at_musoftware.de with
the string "unsubscribe cc65" in the body(!) of the mail.


Date view Thread view Subject view

This archive was generated by hypermail 2.1.3 : 2001-12-14 22:05:39 CET