6502代码中有效的多个间接方向
。
我正在查看一个6502程序,该程序具有多个数组的字节(声音效果数据与特定语音相对应),该程序的长度不同 当前,这涉及在第一个(如果排队)中明确迭代,然后是第二个等,每个语音都有一组用于音量,延迟等的变量集,因此设置了代码以使用这些硬编码的标签。
我想将其汇入一个循环,将这些其他变量和声音效果数据索引。使用索引的地址索引,将变量索引非常简单,但是对声音效果数据进行索引涉及更多的工作,我想知道我是否缺少索引间接和间接索引的解决方案。
以下是我目前在做什么的独立示例。如果可能的话,我想收紧的部分是loadFromtable
中的代码,理想情况下,同时使用x
和y
地址:
.equ Ptr0, 0x80
.equ Ptr1, 0x81
.org 0xFE00
.org 0x0000
Init:
LDX #0xFF
TXS
Main:
LDX #0x00
LDY #0x00
JSR LoadFromTable
; A should be 'H', 0x48
LDX #0x01
LDY #0x00
JSR LoadFromTable
; A should be 'B', 0x42
LDX #0x02
LDY #0x02
JSR LoadFromTable
; A should be 'A', 0x41
JMP Main
LoadFromTable:
TXA ; Double outer index to account for 16 bit pointers
ASL ; "
TAX ; "
LDA Table,X ; Load the low byte of the array into a pointer
STA Ptr0 ; "
INX ; Load the high byte of the array into the pointer
LDA Table,X ; "
STA Ptr1 ; "
LDA (Ptr0),Y ; Load the character at the inner index into the array
RTS
.org 0x0040
Table:
.word Item0
.word Item1
.word Item2
.org 0x0080
Item0:
.byte 'H', 'E', 'L', 'L', 'O', 0x00
Item1:
.byte 'B', 'O', 'N', 'J', 'O', 'U', 'R', 0x00
Item2:
.byte 'C', 'I', 'A', 'O', 0x00
.org 0x00FA
.word Init
.word Init
.word Init
实现
从@nickwestgate乘坐拆分表的想法,并悬挂了@michael指出的初始指针计算,我已经从类似的东西中移动了:
PROCESS_MUSIC:
; ...
BNE MusDoB
MusChanA:
; ...
LDA MUSICA,X
BNE MusCmdToneA
; ...
JMP MusChanA
MusCmdToneA:
; ...
BNE MusNoteA
; ...
MusNoteA:
; ...
LDA MUSICA,X
; ...
MusDoB:
; ...
BNE MusDoDone
MusChanB:
; ...
LDA MUSICB,X
BNE MusCmdToneB
; ...
JMP MusChanB
MusCmdToneB:
; ...
BNE MusNoteB
; ...
MusNoteB:
; ...
MusDoDone:
RTS
对这个更广泛的子例程:
PROCESS_MUSIC:
LDX #0x01
PerChannel:
; ...
BNE EndPerChannel
LDA MusicTableL,X
STA tmp0
LDA MusicTableH,X
STA tmp1
MusChan:
; ...
LDA (tmp0),Y
BNE MusCmdTone
; ...
BEQ MusChan
MusCmdTone:
; ...
BNE MusNote
; ...
MusNote:
; ...
LDA (tmp0),Y
; ...
EndPerChannel:
DEX
BPL PerChannel
RTS
添加了以下表:
MusicTableL:
.byte <MUSICA
.byte <MUSICB
MusicTableH:
.byte >MUSICA
.byte >MUSICB
这将删除需要我最初使用的loadFromtable
功能,总体上似乎要干净得多。
Issue
I'm looking at a 6502 program that has multiple arrays of bytes (sound effect data corresponding to a particular voice), which are of varying lengths. Currently this involves explicitly iterating through the first (if queued), then the second etc, and each voice has a separate set of variables for volume, delay etc, so the code is set up to use these hard-coded labels.
I'd like to roll this into a loop, indexing into these additional variables and the sound effect data. Indexing into the variables is fairly straightforward, using indexed addressing, but indexing into the sound effect data involves a lot more work, and I'm wondering if I'm missing something in the application of indexed indirect and indirect indexed addressing.
Below is a self-contained example of what I'm doing at the moment. The part I'd like to tighten up, if possible, is the code in LoadFromTable
, ideally with some use of both X
and Y
addressing:
.equ Ptr0, 0x80
.equ Ptr1, 0x81
.org 0xFE00
.org 0x0000
Init:
LDX #0xFF
TXS
Main:
LDX #0x00
LDY #0x00
JSR LoadFromTable
; A should be 'H', 0x48
LDX #0x01
LDY #0x00
JSR LoadFromTable
; A should be 'B', 0x42
LDX #0x02
LDY #0x02
JSR LoadFromTable
; A should be 'A', 0x41
JMP Main
LoadFromTable:
TXA ; Double outer index to account for 16 bit pointers
ASL ; "
TAX ; "
LDA Table,X ; Load the low byte of the array into a pointer
STA Ptr0 ; "
INX ; Load the high byte of the array into the pointer
LDA Table,X ; "
STA Ptr1 ; "
LDA (Ptr0),Y ; Load the character at the inner index into the array
RTS
.org 0x0040
Table:
.word Item0
.word Item1
.word Item2
.org 0x0080
Item0:
.byte 'H', 'E', 'L', 'L', 'O', 0x00
Item1:
.byte 'B', 'O', 'N', 'J', 'O', 'U', 'R', 0x00
Item2:
.byte 'C', 'I', 'A', 'O', 0x00
.org 0x00FA
.word Init
.word Init
.word Init
Implementation
Taking onboard the split table idea from @NickWestgate and hoisting out the initial pointer calculation as noted by @Michael, I've moved from something like this:
PROCESS_MUSIC:
; ...
BNE MusDoB
MusChanA:
; ...
LDA MUSICA,X
BNE MusCmdToneA
; ...
JMP MusChanA
MusCmdToneA:
; ...
BNE MusNoteA
; ...
MusNoteA:
; ...
LDA MUSICA,X
; ...
MusDoB:
; ...
BNE MusDoDone
MusChanB:
; ...
LDA MUSICB,X
BNE MusCmdToneB
; ...
JMP MusChanB
MusCmdToneB:
; ...
BNE MusNoteB
; ...
MusNoteB:
; ...
MusDoDone:
RTS
to this more generalised subroutine:
PROCESS_MUSIC:
LDX #0x01
PerChannel:
; ...
BNE EndPerChannel
LDA MusicTableL,X
STA tmp0
LDA MusicTableH,X
STA tmp1
MusChan:
; ...
LDA (tmp0),Y
BNE MusCmdTone
; ...
BEQ MusChan
MusCmdTone:
; ...
BNE MusNote
; ...
MusNote:
; ...
LDA (tmp0),Y
; ...
EndPerChannel:
DEX
BPL PerChannel
RTS
with the addition of the following tables:
MusicTableL:
.byte <MUSICA
.byte <MUSICB
MusicTableH:
.byte >MUSICA
.byte >MUSICB
This removes the need for the LoadFromTable
function I'd originally been using, and seems much cleaner overall.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一些想法。一个人正在通过已经翻了一番的索引(即,如果您可以安排它,否则它可能已经在较早的阶段已经在蓄能器中)。
另一个正在拆分地址表:
如果您无法将表分开,则可能仍然可以通过这样做来摆脱INX:
自我修改代码可能很有用。在零页上生活将是一个因素:
您还可以查看在存储时是否将Y添加到指针中可以节省任何周期。它可能取决于最常见的路径(即通常不注入ptr2/load+2)。
Here are a few ideas. One is passing in an index that's already doubled (i.e. if you can arrange that, or it might already be in the accumulator at some earlier stage).
Another is splitting up the address tables:
If you can't split up the tables, you can probably still get rid of an INX by doing:
Self modifying code might be useful. Living on page zero will be a factor:
You could also see whether adding Y to the pointer as you store it saves any cycles. It might depend on the most common path used (i.e. if it usually doesn't INC Ptr2/Load+2).
如果您试图在1 MHz 6502上生成实时音频,则我使用每个样本40个字节加上四个声音音乐,加上时间来实际喂食DAC,在我的情况下是两个零页面存储到AUDV0和AUDV1寄存器。
关键是使用该表单的四个代码段的“滚动”序列:
这种方法使在五圈范围内生产四个声音音乐范围是可能的,使用了半率和四分之一播放,底部有两个。八度,但将价值40个字节的零页指针连接起来(几乎是2600的RAM的三分之一!)。如果不需要选择播放速率,并且可以负担得起每个样本的额外256个字节,那么一个人可能会有主要的样本循环,例如:
另外两个代码需要在上层之间进行某个时间运行
of OutCounter
的位置,何时再次清楚,从那时起,它很清楚,何时重新设置。代码的后半部分将相当长,但是只需要每256个样本一次运行一次,并且可以容纳任意循环部分。
If you're trying to generate real-time audio on 1 MHz 6502, I've done four-voice music using 40 bytes per sample plus the time to actually feed the DAC(s), which in my case was two zero-page stores to the AUDV0 and AUDV1 registers.
The key was to use a "rolling" sequence of four code snippets of the form:
This approach made it possible to produce four-voice music range over a five-octave range, using half-rate and quarter-rate playback for the bottom two octaves, but ties up 40 bytes worth of zero-page pointers (almost a third of the total RAM on the 2600!). If a choice of playback rates was not required, and one could afford to pad each sample out by an extra 256 bytes, one could have the main sample loop be something like:
Two other pieces of code would need to run sometime between when the upper bit of
outCounter
is set and when it's clear again, and again between then it's clear and when it's re-set.The latter portion of the code would be fairly long, but it would only need to be run once every 256 samples, and could accommodate arbitrary looping sections.