2016-02-02 13 views
2

Я пытаюсь переключить нормальный ход выполнения программы в то время как прерывание, возвращается:Модифицированный 6502 прерывания Возвращает

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 

Я написал этот код accourding к этому источнику: http://6502.org/tutorials/interrupts.html#1.3

enter image description here

Но дело PHA в crash, как переключить нормальный поток LOOP1 на LOOP2 в прерывание?

+2

@DavidHoelzer вы поняли код, что часть просто настройки прерываний, и две петли являются два процесса, которые он хочет, чтобы запланировать. Тем не менее, отключение дальнейших прерываний в обработчике звучит как хорошая идея. Кроме того, сохраненные вещи уже в стеке должны быть удалены, иначе вы получите переполнение стека, если вы просто продолжаете толкать вещи. Порядок тоже кажется неправильным, вам нужно использовать то же, что и на диаграмме. – Jester

+0

О да, вы правы. Я пропустил < and > для кода IRQ. Прошло немало времени. :) –

+2

Непонятно, пытаетесь ли вы манипулировать содержимым стека или писать самомодифицирующийся код. Вы нажали новый адрес возврата, но предыдущий все еще существует. У вас быстро закончится стек. Я предлагаю «PHA; ТХ; PHA; TSX', а затем модифицировать уложенный адрес возврата путем индексации 'X', до восстановления регистров и выполнения' RTI'. –

ответ

1

Простой способ:

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

Но для более сложного управления задачами, мы должны сохранить A, X, Y регистров для каждая задача:

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

Не будет проблем с кодом 'tsx: lda $ 101, x: и т. Д., Когда стек только что завершился с $ 100 до $ 1ff? Вероятно, не для вашего случая, когда вы задумчиво разделяете пространство стека, но в целом, если стек используется только для стека прерываний, вызова процедур и возможного PHA/PLA, и нет очевидной необходимости беспокоиться о точной позиции стека вообще. – lvd

3

Простейшая вещь, вероятно, состоит из двух областей стека - по одной для каждой задачи. Например, $ 100- $ 17f и $ 180- $ 1ff. Тогда, вы бы иметь свой код прерывания переключения задач, как это:

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

Это аккуратный подход. Возможно, стоит отметить, что аппаратное обеспечение не обеспечивает каких-либо границ стека. Поэтому, если B попадает в пространство стека A, A может начать делать очень странные вещи. Переключатель задач может выполнять проверки целостности диапазона. Но некоторые обходные ошибки все еще не поддаются определению. – Core

+1

@lvd, TSX является ключом к решению, которое я написал ниже, я тестировал, и он работает! Спасибо! – Digerkam

+1

Аппаратное обеспечение не обеспечивает общие границы стека; единственное различие заключается в том, что предел составляет 128 байт, а не 256, и вы будете топтать верхнюю часть чужого стека вместо своего собственного, если вы бесшумно переполняете. – Tommy