我是编码在旧的,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的实现实现了一些我的例程中没有的魔力。
发布于 2019-06-03 00:54:09
C语言和汇编语言程序有一个主要的区别:
我不知道你的C编译器的库,但是outp()
要么等同于out dx,ax
,要么等同于out dx,al
。
(我猜它等同于out dx,al
。)
然而,在你的汇编程序中,你有时用out dx,ax
代替outp()
,有时用out dx,al
代替。两者中肯定有一个是错的。
如果真正的声卡具有8位ISA接口,并且 outp()
等同于out dx,al
,则使用以下汇编程序代码:
移动ax,注册输出dx,ax增量dx移动,注册输出dx,al
..。取自你的汇编程序,等于下面的C程序:
outportb(address, regnum);
outportb(address + 1, regnum >> 8); // This may cause the noise
outportb(address + 1, regval);
尝试用out dx,al
替换out dx,ax
。
(不幸的是,我不知道DOSbox是用8位还是16位接口模拟声卡。)
请注意
读完我之前写的内容后,您可能会尝试仅使用一条out
指令同时写入寄存器和值:
mov al,regnum
mov ah,regval
out dx,ax
很有可能这将与8位连接器的真正声卡一起工作。
但是,这可能不适用于具有16位连接器的真实声卡(也可能不适用于DOSbox之类的模拟器)。
https://stackoverflow.com/questions/56416630
复制相似问题