Как создать задержку на асм для МОП 6502

Я новичок в ASM и пытаюсь понять, как создать задержку для следующего кода:

org $1000

loop: inc $d021
    jmp loop

person icodenosleep    schedule 09.02.2014    source источник
comment
Да, это просто программа смены переднего плана   -  person icodenosleep    schedule 09.02.2014
comment
Ты имеешь в виду фон?   -  person Michael    schedule 09.02.2014
comment
Если под задержкой вы подразумеваете ожидание следующей строки сканирования, добавьте внутренний цикл, ожидающий изменения $d012.   -  person Michael    schedule 09.02.2014
comment
Нет, я имею в виду подождав секунду, а затем изменив цвет (извините, что перепутал)   -  person icodenosleep    schedule 09.02.2014
comment
Затем подождите, пока $d012 не изменится 320*50 раз, или используйте растровое прерывание, при котором вы считаете кадры.   -  person Michael    schedule 09.02.2014


Ответы (4)


Комментарии достаточно ясны, я думаю.

Пример кода для изменения цвета каждого кадра (1/50 секунды)

        sei       ; enable interrupts

loop1:  lda #$fb  ; wait for vertical retrace
loop2:  cmp $d012 ; until it reaches 251th raster line ($fb)
        bne loop2 ; which is out of the inner screen area

        inc $d021 ; increase background color

        lda $d012 ; make sure we reached
loop3:  cmp $d012 ; the next raster line so next time we
        beq loop3 ; should catch the same line next frame

        jmp loop1 ; jump to main loop

Пример кода для смены цвета каждую секунду

counter = $fa ; a zeropage address to be used as a counter

        lda #$00    ; reset
        sta counter ; counter

        sei       ; enable interrupts

loop1:  lda #$fb  ; wait for vertical retrace
loop2:  cmp $d012 ; until it reaches 251th raster line ($fb)
        bne loop2 ; which is out of the inner screen area

        inc counter ; increase frame counter
        lda counter ; check if counter
        cmp #$32    ; reached 50
        bne out     ; if not, pass the color changing routine

        lda #$00    ; reset
        sta counter ; counter

        inc $d021 ; increase background color
out:
        lda $d012 ; make sure we reached
loop3:  cmp $d012 ; the next raster line so next time we
        beq loop3 ; should catch the same line next frame

        jmp loop1 ; jump to main loop
person Emir Akaydın    schedule 10.02.2014
comment
Вы можете использовать Y вместо нулевой страницы и A. И вместо увеличения счетчика уменьшите его, чтобы вы могли неявно BNE на Y. Короче, быстрее, более идиоматично. Смотрите мой запрос на редактирование. - person youri; 29.08.2014
comment
Поскольку я люблю кодировать 256-байтовые интро, я использую много других приемов, таких как самомодифицирующийся код, недопустимые коды операций, общие значения регистров и т. д. Но этот пример кода написан специально для тех, кто сказал, что я новичок в ASM. Таким образом, это не оптимизированный ни по размеру, ни по циклу исходный код. Это пример кода для начинающих, и я полагаю, что обратные циклы могут их запутать. - person Emir Akaydın; 02.09.2014
comment
Я бы сказал, что использование нулевой страницы сложнее, чем использование регистра Y, независимо от того, как вы выполняете цикл (обратный или прямой), особенно если A используется для двух целей. Мое предложение состояло не в том, чтобы уменьшить размер кода или количество циклов (это побочный эффект), а в том, чтобы повысить читабельность. Возможно, использование регистра Y вперед с явным указанием CPY сделало бы еще более приятное решение для начинающих. - person youri; 03.09.2014

Например:

loop: ldx $d021
      inx
      stx $d021
      cpx #100
      bne loop
person user2699113    schedule 09.02.2014
comment
Это не изменяет $d021 один раз в секунду, оно изменяет его один раз каждые 15 циклов, пока его значение не станет #100 (которое является полностью переменным, поскольку мы не знаем, с чего начать $d021). - person Eight-Bit Guru; 09.02.2014
comment
В самом начале пользователь 3049038 писал только о цикле, поэтому я написал цикл для него. Больше информации о том, что $d021 является регистром HW, не было, так что мой ответ правильный. - person user2699113; 10.02.2014
comment
Адреса $D020/01 хорошо известны нам, динозаврам. Особенно в сочетании с 6502/10. ;) - person Devolus; 10.02.2014
comment
Возможно для дино C64. У меня Atari 800xl, поэтому я не знаю этот регистр :) - person user2699113; 10.02.2014

Как насчет этого? Это должно изменить фон, подождите 4 секунды, затем снова измените его. Повторяйте вечно.

Обратите внимание, что вы можете изменить количество секунд на любое значение от 0 до 255.

Это для NTSC машин, но вы можете изменить 60 на 50 для PAL.

main:
    inc $D021

    ldx #4          //  Wait 4 seconds
loop1:
    ldy #60
loop2:

waitvb:
    bit $D011
    bpl waitvb
waitvb2:
    bit $D011
    bmi waitvb2

    dey
    bne loop2
    dex
    bne loop1

    jmp main
person cbmeeks    schedule 02.05.2016

Если вы можете гарантировать, что код не пересекает границу страницы, полезный подход состоит в том, чтобы иметь пару байтов где-то в ОЗУ, которые будут содержать вычисленный адрес перехода, и использовать косвенный переход в что-то вроде следующего:

TableStart:
    cmp #$C9
    cmp #$C9
    cmp #$C9
    cmp #$C9
    cmp #$C9
    ...
TableEnd:
    nop

Если вектор перехода указывает на tableEnd, код достигнет инструкции после NOP через семь циклов. Если он указывает на один байт раньше, восемь циклов. Два байта раньше, девять циклов и т. д. Установка вектора перехода может занять некоторое время, но сама задержка будет плавно регулироваться от семи циклов до любого более высокого значения с шагом в один цикл. Флаги будут удалены, но никакие регистры не будут затронуты.

person supercat    schedule 18.05.2016