Упражнение по самоизменяющейся процедуре копирования памяти, 6502 ASM

Ниже приведена моя самоизменяющаяся процедура копирования памяти на Commodore 64.

я написал char codes а также number of repeats в таблице и заполнил screen_ram с этой рутиной.

Я ищу предложения по оптимизации. Мой приоритет - память в этом случае.

memCopy:    
  sourceAddress=*+1 ; mark self modifying addrres
fetchNewData:
  lda data_table    ; read char value into A
  ldx data_table+1  ; read repeat value into x
  inc sourceAddress     
  inc sourceAddress 

  cpx #00           ; if X=0 
  beq end           ; finish copying

  destination=*+1
- sta SCREEN_RAM
  inc destination
  dex
  bne -

  jmp fetchNewData

end:
  rts   

; data format:  <char>,<number of repeats>,[<char>,<number of repeats>,...],00,00

data_table: 
!by 01,03,02,02,......,00,00

3 ответа

Решение

Правильное увеличение адреса инструкции должно быть сделано так:

address=*+1
    lda self_modifying_address
    inc address+0
    bne *+5
    inc address+1

таким образом, вероятно, пренебрегая всей экономией памяти для самоизменяемого кода.

Я предлагаю другой подход, который включает самоизменяющиеся адреса команд только там, где необходима абсолютность, а также сохраняет переменные памяти в инструкциях.

.loop
fetch_ptr=*+1
    ldx #0
    lda filler_bytes,x ;have two tables, first contains only filler bytes,
    ldy repeat_bytes,x ;second only repeat counts
    beq .exit
    inc fetch_ptr      ;this way you save 1 increment

fill_ptr=*+1
    ldx #0
.fill
    sta SCREEN_RAM,x
    inx
    bne +
    inc .fill+2 ;only self-modify high byte of address in the instruction
+   dey
    bne .fill

    stx fill_ptr

    jmp .loop
.exit
    rts


filler_bytes !byte 1,2,3,4,5,4,3,2,1
repeat_bytes !byte 4,4,5,5,6,6,5,5,4,0

JMP fetchNewData -> BEQ fetchNewData, Переехать INC sourceAddress после BEQ end и нет необходимости от CPX #0 (после LDX). На 3 байта меньше.

В дополнение к предложениям i486, если data_table ограничено 128 значениями (включая завершающие 0,0), тогда вы можете сохранить пару байтов (и много циклов), избегая самоизменения LDAs и используя вместо этого регистр Y.

Я показал все это ниже. Вы также можете сохранить другой байт (удалить один INYЗапустив data_table значения в две отдельные таблицы.

В качестве альтернативы вы можете использовать Y для индексации SCREEN_RAMно я не C64 парень...

  ldy #0
fetchNewData:
  lda data_table,y  ; read char value into A
  iny               ; [could remove if two tables]
  ldx data_table,y  ; read repeat value into x
  beq end           ; finish copying [x=0]
  iny

  destination=*+1
- sta SCREEN_RAM
  inc destination
  dex
  bne -
  beq fetchNewData

end:
  rts   

; data format:  <char>,<number of repeats>,[<char>,<number of repeats>,...],00,00

data_table: 
!by 01,03,02,02,......,00,00
Другие вопросы по тегам