Упражнение по самоизменяющейся процедуре копирования памяти, 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), тогда вы можете сохранить пару байтов (и много циклов), избегая самоизменения LDA
s и используя вместо этого регистр 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