2016-02-02 3 views
2

Je suis en train de passer le flux normal du programme tandis qu'un rendement d'interruption:modifié 6502 Interrompre retour

START 
    SEI 
    LDX #<IRQ 
    LDY #>IRQ 
    STX $FFFE 
    STY $FFFF 
    CLI 

LOOP1 
    INC $D020 
    JMP LOOP1 

LOOP2 
    INC $D021 
    JMP LOOP2 

IRQ 
    STA SAVEA+1 
    STX SAVEX+1 
    STY SAVEY+1 

    // Some Routines 

    LDA #$00 
    PHA 
    LDA #<LOOP2 
    PHA 
    LDA #>LOOP2 
    PHA 

SAVEA 
    LDA #$00 
SAVEX 
    LDX #$00 
SAVEY 
    LDY #$00 
    RTI 

J'ai écrit ce code, mené selon cette source: http://6502.org/tutorials/interrupts.html#1.3

enter image description here

Mais la cause de PHA crash, comment passer le flux normal LOOP1 à LOOP2 dans une interruption?

+2

@DavidHoelzer vous avez mal compris le code, cette partie est mise juste les interruptions et les deux boucles sont les deux processus qu'il veut programmer. Cela dit, désactiver d'autres interruptions dans le gestionnaire semble être une bonne idée. En outre, les éléments sauvegardés déjà sur la pile doivent être supprimés, sinon vous aurez un débordement de pile si vous continuez simplement à pousser les choses. L'ordre semble également faux, vous devez utiliser le même que sur le diagramme. – Jester

+0

Oh oui, vous avez raison. J'ai négligé le < and > pour le code IRQ. Cela fait longtemps. :) –

+2

Il n'est pas clair si vous essayez de manipuler le contenu de la pile ou d'écrire du code auto-modifiable. Vous avez activé une nouvelle adresse de retour, mais la précédente est toujours présente. Vous allez rapidement manquer de pile. Je suggère "PHA; TXA; PHA; TSX' puis en modifiant l'adresse de retour empilée en indexant 'X', avant de restaurer les registres et de faire un' RTI'. –

Répondre

1

façon simple est:

TSX 
LDA #$00 
STA $0101,X // Processor Status 
LDA #<LOOP2 
STA $0102,X // Task Low Address 
LDA #>LOOP2 
STA $0103,X // Task High Address 

Mais pour la gestion des tâches plus complexes, nous devons sauver A, X, Y registres pour chaque tâche:

START 
    SEI 
    LDX #<IRQ 
    LDY #>IRQ 
    STX $FFFE 
    STY $FFFF 
    CLI 

LOOP1 
    INC $D020 
    JMP LOOP1 

LOOP2 
    INC $D021 
    JMP LOOP2 

IRQ 
    STA $FF 
    STX $FE 
    STY $FD 
    LDX TASK+1 
    CPX TASK 
    BEQ CONT 
    LDY TASKI,X 
    TSX 
    LDA $0101,X 
    STA TASKS+0,Y 
    LDA $0102,X 
    STA TASKS+1,Y 
    LDA $0103,X 
    STA TASKS+2,Y 
    LDA $FF 
    STA TASKS+3,Y 
    LDA $FE 
    STA TASKS+4,Y 
    LDA $FD 
    STA TASKS+5,Y 
    LDA TASK 
    STA TASK+1 
CONT 

    // Change Task 
    LDA TASK 
    CLC 
    ADC#$01 
    AND #$01 
    STA TASK 


    LDX TASK 
    CPX TASK+1 
    BEQ CONT2 
    STX TASK+1 
    LDY TASKI,X 
    TSX 
    LDA TASKS+0,Y 
    STA $0101,X 
    LDA TASKS+1,Y 
    STA $0102,X 
    LDA TASKS+2,Y 
    STA $0103,X 
    LDA TASKS+3,Y 
    STA $FF 
    LDA TASKS+4,Y 
    STA $FE 
    LDA TASKS+5,Y 
    STA $FD 
CONT2 
    LDA $FF 
    LDX $FE 
    LDY $FD 
    RTI 

TASK 
    .BYTE 0,0 
TASKI 
    .BYTE 0,6,12,18,24,30,36 
TASKS 
    .BYTE 0,<LOOP1,>LOOP1,0,0,0 
    .BYTE 0,<LOOP2,>LOOP2,0,0,0 
+1

Y aura-t-il un problème avec le code 'tsx: lda $ 101, x: etc.' quand la pile vient de passer de $ 100 à $ 1ff? En général, si la pile est utilisée uniquement pour l'empilement des interruptions, l'appel des procédures et l'éventuel PHA/PLA, il n'y a aucun besoin évident de s'inquiéter de la position exacte de la pile. – lvd

3

La chose la plus simple est probablement d'avoir deux zones de pile - une pour chaque tâche. 100 $ - 17 $ et 180 $ - 1 $, par exemple. Ensuite, vous auriez votre code de commutation de tâche d'interruption comme ceci:

pha 
    txa 
    pha 
    tya 
    pha ;saving task's registers on its stack, 
     ;where flags and PC are already saved 
     ;by entering the interrupt 

    tsx 
    stx ... ;save task's stack position 

    ... ;select new task to run/etc. 

    ldx ... 
    txs ;load other task's stack position 

    pla 
    tay 
    pla 
    tax 
    pla ;restore other task's registers 

    rti ;and finally continue other task 
+1

C'est une approche soignée. Peut-être que cela vaut la peine de souligner que le matériel n'impose aucune limite de pile. Donc, si B finit dans un espace de pile, A peut commencer à faire des choses très étranges. Le sélecteur de tâches peut effectuer certaines vérifications d'intégrité de plage. Mais certaines erreurs enveloppantes sont encore indétectables. – Core

+1

@lvd, TSX est la clé de la solution que j'ai écrite ci-dessous, j'ai testé et ça marche! Je vous remercie! – Digerkam

+1

Le matériel n'applique pas les limites de la pile en général; la seule différence est que la limite est de 128 octets au lieu de 256 et que vous écraserez le sommet de la pile de quelqu'un d'autre à la place du vôtre si vous débordez silencieusement. – Tommy