自修改内存复制例程练习,6502 ASM
Exercise in self modifying memory copy routine, 6502 ASM
下面是我在Commodore 64上的内存拷贝自修改例程。
我在 table 中写了 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
JMP fetchNewData
-> BEQ fetchNewData
。将 INC sourceAddress
移到 BEQ end
之后,CPX #0
(LDX
之后)就没有必要了。少了 3 个字节。
除了 i486 的建议之外,如果 data_table
被限制为 128 个值(包括终止 0,0),那么您可以通过避免自修改 LDA
s 并改用 Y 寄存器。
我已经在下面展示了所有内容。您还可以通过将 data_table
值放入两个单独的表中来保存另一个字节(删除一个 INY
)。
或者你可以使用 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
正确的指令地址增量应该是这样的:
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
下面是我在Commodore 64上的内存拷贝自修改例程。
我在 table 中写了 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
JMP fetchNewData
-> BEQ fetchNewData
。将 INC sourceAddress
移到 BEQ end
之后,CPX #0
(LDX
之后)就没有必要了。少了 3 个字节。
除了 i486 的建议之外,如果 data_table
被限制为 128 个值(包括终止 0,0),那么您可以通过避免自修改 LDA
s 并改用 Y 寄存器。
我已经在下面展示了所有内容。您还可以通过将 data_table
值放入两个单独的表中来保存另一个字节(删除一个 INY
)。
或者你可以使用 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
正确的指令地址增量应该是这样的:
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