6502: Fix longmp
authorAlan Cox <alan@linux.intel.com>
Wed, 13 Dec 2017 19:13:00 +0000 (19:13 +0000)
committerAlan Cox <alan@linux.intel.com>
Wed, 13 Dec 2017 19:13:00 +0000 (19:13 +0000)
This is ugly. For the 6502/6509/65C02 and friends we need to just deal with the
8bit S register. For the 65C816 we have to change the low 8bits of S only, while
keeping interrupts off as we might otherwise get swapped out and change S mid
calculation.

Not always my favourite processor for multi-tasking..

Library/libs/Makefile.6502
Library/libs/longjmp_6502.s [new file with mode: 0644]

index 7a90b73..142481c 100644 (file)
@@ -8,7 +8,7 @@ ASM_OPT = -o
 LINKER_OPT = -o
 SRC_CRT0 = crt0_6502.s crt0nostdio_6502.s
 OBJ_CRT0 = $(SRC_CRT0:.s=.o)
-SRC_ASM =
+SRC_ASM = longjmp_6502.s
 OBJ_ASM = $(SRC_ASM:.s=.o)
 #
 #      Library routines. cc65 has its own library which has some overlap.
diff --git a/Library/libs/longjmp_6502.s b/Library/libs/longjmp_6502.s
new file mode 100644 (file)
index 0000000..688a141
--- /dev/null
@@ -0,0 +1,115 @@
+;
+; 1998-06-06, Ullrich von Bassewitz
+; 2015-09-11, Greg King
+;
+; void __fastcall__ longjmp (jmp_buf buf, int retval);
+;
+; Modified for the Fuzix 65C816 setup
+;
+
+        .export         _longjmp
+        .import         popax
+        .importzp       sp, ptr1, ptr2
+       .importzp       tmp1,tmp2
+
+       .p816
+       .a8
+       .i8
+
+_longjmp:
+        sta     ptr2            ; Save retval
+        stx     ptr2+1
+        ora     ptr2+1          ; Check for 0
+        bne     @L1
+        inc     ptr2            ; 0 is illegal, according to the standard ...
+                                ; ... and, must be replaced by 1
+@L1:    jsr     popax           ; get buf
+        sta     ptr1
+        stx     ptr1+1
+        ldy     #0
+
+; Get the old parameter stack
+
+        lda     (ptr1),y
+        iny
+        sta     sp
+        lda     (ptr1),y
+        iny
+        sta     sp+1
+
+;
+; Detection code based on an idea by Jody Bruchon
+;
+; Party time we have two cases
+;
+; 6502/65C02/65WD02 etc                - S is 8bit
+; 65C816                       - S is 16bit and we must merge the saved low
+;                                8 with the current high 8 with IRQs off
+;                                due to the sucky CPU design
+;
+       lda #$00
+       inc                     ; 65C02 or later will add one
+       cmp #$01
+       bmi is_8bit             ; 6502so skip
+;
+;      We can now safely play with xba to see if it's an 816.
+; 
+       xba                     ; 65c02 the xba's do nothing            
+       dec                     ; so a goes to 0
+       xba                     ; while 65C816 keeps it as one
+       cmp #$01
+       bmi is_8bit
+;
+;      16bit mode. Please ensure your barf bucket is to hand
+;
+       sei                     ; Interrupts off
+       rep #$30
+       .a16
+       .i16
+       tsx                     ; 16 bit stack pointer into A
+       txa
+       sep #$20
+       .a8
+        lda     (ptr1),y       ; Restore low 8bits of SP only
+       rep #$20
+       .a16
+
+        iny                    ; Move down struct
+
+       tax                     ; Restore stack pointer 16bits
+       txs
+
+       sep #$30
+       .a8
+       .i8
+
+       cli                     ; Interrupts back on
+       bra pop_out
+
+;
+; 8bit is nice and simple
+;
+is_8bit:       
+; Get the old stack pointer
+
+        lda     (ptr1),y
+        iny
+        tax
+
+        txs
+
+pop_out:
+
+; Get the return address and push it on the stack
+
+        lda     (ptr1),y
+        iny
+        pha
+        lda     (ptr1),y
+        pha
+
+; Load the return value and return to the caller
+
+        lda     ptr2
+        ldx     ptr2+1
+        rts