我是编码在旧的,1994年时代的游戏编程乐趣,并输出数据从一个RAD文件到OPL3 FM合成芯片。我要离开DOSBox了。
为了提高处理硬件寄存器时的性能(特别是因为我正在通过定时中断更新FM Synth芯片(以保持节拍),并且希望尽快回到主代码中),我考虑在汇编中重写我的寄存器输出。
然而,虽然这种方法有效,但它似乎在synth芯片的输出中引入了失真,这在我使用纯C的outportb时是不存在的,我想我应该在这里询问是否有人能告诉我发生了什么。“out dx,al”和“outp(int,char)”之间有什么特别的、细微的区别吗?
OPLStatus status = NONE;
unsigned int primAd;
unsigned int secAd;
unsigned int backAd;
void OPLWriteImpl(void *argument, unsigned int registerNumber, unsigned char registerValue) {
(void)argument; /* Unused variable */
if(status == OPL3 || status == DUALOPL2) {
if(registerNumber <= REGISTER_THRESHOLD) {
outp(primAd, registerNumber);
outp(primAd+1, registerValue);
}
else {
outp(secAd, registerNumber);
outp(secAd+1, registerValue);
}
}
else {
outp(backAd, registerNumber);
outp(backAd+1, registerValue);
}
}
EXTRN status:WORD, primAd:WORD, backAd:WORD
.CODE
PUBLIC OPLWriteImpl
OPLWriteImpl PROC FAR C argument:DWORD, regnum:WORD, regval:BYTE
cmp status,0 ; if status == 0, go to OPL3
je three
cmp status,2 ; if status == DUAL, also go to OPL3
jne two ; otherwise, go to OPL2
three:
mov dx,primAd ; put OPL3 primary bank in dx
cmp regnum,100h ; check if regnum <=than threshold (256)
jle prim ; if so, go straight to primary bank
inc dx ; otherwise, writing to secondary bank (primary+2)
inc dx
prim:
mov ax,regnum ; put the register number in ax
out dx,ax ; output to register
inc dx ; go to data address
mov al,regval ; put the value in al
out dx,al ; output to data
jmp done ; finished
two:
mov dx,backAd
mov ax,regnum
out dx,ax
mov cx,6
loopOne:
in al,dx
loop loopOne
inc dx
mov al,regval
out dx,al
dec dx
mov cx,36
loopTwo:
in al,dx
loop loopTwo
done:
ret ; return to C
OPLWriteImpl ENDP
当使用我的C例程时,音乐像在RAD Tracker中一样正确输出。但是当我使用我的汇编程序时,一些乐器似乎有一种奇怪的沙哑的声音。我真的不能责怪Dosbox仿真,因为,就像我说的,它在纯C语言中工作得很好。区别并不是非常惊人,但它非常明显。我唯一的猜测是outportb的实现实现了一些我的例程中没有的魔力。
https://stackoverflow.com/questions/56416630
复制相似问题