Есть ли существенная разница между outportb и инструкцией out в сборке 8086? - PullRequest
1 голос
/ 02 июня 2019

Я пишу в старом DOS, выпущенном в 1994 году, для забавы по программированию игр, и выводю данные из файла RAD в чип OPL3 FM Synthesis. Я убегаю из DOSBox.

В попытке повысить производительность при работе с аппаратными регистрами (особенно с учетом того, что я обновляю чип FM Synth с помощью прерывания по времени (чтобы сохранить темп) и хочу вернуться к основному коду как можно быстрее), я подумал переписать мой регистр выведен в сборку.

Однако, хотя это работает, кажется, что на выходе синтезаторного чипа появляются искажения, которых нет, когда я использую outportb чистого C, и я решил попросить здесь посмотреть, может ли кто-нибудь сказать мне, что происходит. Есть ли какая-то конкретная, тонкая разница между «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 творит магию, которой нет в моей рутине.

1 Ответ

4 голосов
/ 02 июня 2019

В 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,ax на out dx,al.

(К сожалению, я не знаю, имитирует ли DOSbox звуковую карту с 8-битным или 16-битным разъемом.)

Обратите внимание

После прочтения того, что я написал ранее, вы можете попытаться использовать только одну out инструкцию для записи регистра и значения одновременно:

mov al,regnum
mov ah,regval
out dx,ax

С большой вероятностью это будет работать с реальной звуковой картой с 8-битным разъемом.

Однако это может не работать на реальных звуковых картах с 16-битным разъемом (и, возможно, также не на симуляторе, таком как DOSbox).

...