- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在使用 1994 年时代的旧 DOS 编写游戏编程乐趣,并将数据从 RAD 文件输出到 OPL3 FM 合成芯片。我正在运行 DOSBox。
为了在处理硬件寄存器时提高性能(特别是因为我正在通过定时中断更新 FM 合成器芯片(以保持节奏)并希望尽快回到主代码)我想重写我的寄存器在汇编中输出。
然而,虽然这有效,但它似乎在合成器芯片的输出中引入了失真,而当我使用纯 C 的输出端口 b 时,这种失真是不存在的,我想我会在这里问问是否有人能告诉我发生了什么。我遗漏的“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 中一样。但是当我使用我的 assembly 例程时,一些乐器似乎发出奇怪的低沉声音。我真的不能责怪 Dosbox 仿真,因为就像我说的,它在纯 C 上工作得很好。区别不是特别大,但非常明显。我唯一的猜测是 outportb 的实现做了一些我的例程中没有的魔法。
最佳答案
C 和汇编程序有一个主要区别:
我不知道你的 C 编译器的库,但是 outp()
要么等同于 out dx,ax
要么等同于 out dx,al
.
(我猜它等同于out dx,al
。)
但是,在您的汇编程序中,您有时会将 outp()
替换为 out dx,ax
,有时会替换为 out dx,al
。两者之一一定是错误的。
如果一个真正的声卡有一个 8 位 ISA 连接器并且 outp()
等同于out dx,al
,下面汇编代码:
mov ax,regnum
out dx,ax
inc dx
mov al,regval
out 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 这样的模拟器)。
关于c - outportb和8086汇编中的out指令有明显区别吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56416630/
我有一段代码试图使用 outportb(),但在 MinGw 上编译它时出现以下错误。 C:\Users\A_TOMAR\AppData\Local\Temp\ccYPvctv.o:dsp.c:(.t
我是一名优秀的程序员,十分优秀!