Режим X в сборке x86-16, почему плоскость 1 не печатается, а все остальные плоскости не в правильном порядке?

Я пишу в TASM 3.0 на DosBox 0.74, и я пытаюсь писать в режиме x (изменено 13h, unchained mode 13), но здесь вы можете видеть на изображении, это не Совершенно верно. Кажется, что плоскость 1 (вторая плоскость) вообще не печатается, а все остальные находятся в неправильном порядке. Я знаю, что код здесь неэффективен, но я хочу заставить его работать, а затем очистить его.

Вывод

proc showBMP
    push cx
    mov ax, 0A000h
    mov es, ax
    mov cx, [BMPHeight]
    mov ax, [BMPWidth]
    xor dx, dx
    mov si, 4
    div si
    mov bp, dx
    mov dx, [BMPX]
    showBMP_nextLine:
        call VGAPlaneStartBMP
        push cx
        push dx
        mov di, cx
        add di, [BMPY]
        mov cx, di
        shl cx, 6
        shl di, 8
        add di, cx
        add di, dx
        mov ah, 3fh
        mov cx, [BMPWidth]
        add cx, bp
        mov dx, offset BMPMaxLine
        int 21h
        cld
        mov cx, [BMPWidth]
        mov si, offset BMPMaxLine
        showBMP_nextLine_movsbLoop:
            push cx
            push di
            shr di, 2
            mov cl, [ds:si]
            mov [es:di], cl
            inc [VGAPlane]
            inc si
            pop di
            inc di
            pop cx
            call VGAPlaneSelect
        loop showBMP_nextLine_movsbLoop
        pop dx
        pop cx
    loop showBMP_nextLine
    pop cx
    ret
endp showBMP

Здесь вы можете увидеть процедуру печати растрового файла, которая отлично работала в режиме 13 цепочки 4.

  • BMPHeight - как следует из названия, это высота изображения
  • BMPWidth - то же
  • BMPX - где изображение начинается на экране (координата x)
  • BMPY - то же, но координата Y
  • BMPMaxLine - массив из 320 работает как буфер
  • VGAPlane - 0/1/2/3 один из самолетов
  proc VGAPlaneStartBMP
       push ax
       push bx
       mov ax, [BMPX]
       mov bx, offset PlaneByX
       add bx, ax
       mov al, [bx]
       mov [VGAPlane], al
       pop bx
       pop ax
       call VGAPlaneSelect
       ret
   endp VGAPlaneStartBMP

Эта процедура для каждой строки печати выбирает плоскость по начальному x строки:

  • PlaneByX - MAX_WIDTH / NUMBER_OF_PLANES дубли (PLANES), СБРОС

  • MAX_WIDTH - 320, NUMBER_OF_PLANES - 4, PLANES - 0, 1, 2, 3,

proc VGAPlaneSelect
        push ax
        push dx
        mov al, 02h
        mov dx, 03C4h
        out dx, al
        VGAPlaneSelect_start:
        cmp [VGAPlane], 0
        jne VGAPlaneSelect_0
            mov al, 0h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_0:
        cmp [VGAPlane], 1
        jne VGAPlaneSelect_1
            mov al, 1h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_1:
        cmp [VGAPlane], 2
        jne VGAPlaneSelect_2
            mov al, 4h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_2:
        cmp [VGAPlane], 3
        jne VGAPlaneSelect_3
            mov al, 8h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_3:
            mov [VGAPlane], 0
            jmp VGAPlaneSelect_start
        VGAPlaneSelect_end:
        inc dx
        out dx, al
        pop dx
        pop ax
        ret
    endp VGAPlaneSelect

И напоследок этот код - при выборе самолета.


person Erik Gelfat    schedule 22.01.2020    source источник
comment
Интересная проблема! Помните, что Stack Overflow - это сайт вопросов и ответов. У вас много деталей, и это здорово. Но можете ли вы отредактировать свое сообщение, чтобы включить в него вопрос? Чем конкретнее, тем лучше. Кроме того, в наши дни 16-битное прямое VGA-программирование является очень нишевым, поэтому ссылки на ссылки (например, по Mode X) могут быть полезны.   -  person Jonathon Reinhart    schedule 22.01.2020
comment
Вы запускаете этот код на голом железе? ВМ? Какая версия гипервизора и прошивки VGA? Там тоже может быть ошибка.   -  person Jonathon Reinhart    schedule 22.01.2020
comment
@JonathonReinhart Слава Джонатону, я отредактировал пост, чтобы он был более понятным, я запускаю код на DosBox, я не знаю, как я могу проверить версию гипервизора и прошивки VGA, но я предполагаю, что в DosBox он эмулирует стабильный, наверное.   -  person Erik Gelfat    schedule 22.01.2020
comment
У вас есть 0, 1, 4, 8 вместо 1, 2, 4, 8 для бит плоскости. Кроме того, почему бы вам не заменить всю логику VGAPlaneSelect на mov al, 1; mov cl, [VgAPlane]; shl al, cl   -  person fuz    schedule 22.01.2020
comment
Так что никакого гипервизора, просто укажите версию DOSBox, которую вы используете.   -  person Jonathon Reinhart    schedule 22.01.2020
comment
@fuz справа, в brackeen.com/vga/unchain.html говорится: выберите самолет, на котором вам нужно отправить 2 ^ plane в порт 0x3C5, для вашего второго пункта, вы правы, мой код сейчас в беспорядке, но я радикально уберу код после того, как увижу, что он работает, но спасибо за это будет использовать это.   -  person Erik Gelfat    schedule 22.01.2020
comment
@JonathonReinhart Я использую DosBox 0.74   -  person Erik Gelfat    schedule 22.01.2020
comment
@ErikGelfat Мое предложение устранило вашу проблему? Если да, напишите это как ответ, чтобы другие знали, что ваш вопрос решен.   -  person fuz    schedule 22.01.2020
comment
@fuz ммм, к сожалению, нет, теперь он ничего не печатает   -  person Erik Gelfat    schedule 22.01.2020
comment
@ErikGelfat Это прискорбно. Попробуйте просто заменить 0, 1, 4, 8 на 1, 2, 4, 8. Вполне вероятно, что написанный мной код на основе shl не работает как есть; это было больше предназначено для вдохновения для реализации вашего собственного дизайна.   -  person fuz    schedule 22.01.2020
comment
@fuz о, вау, это странно, потому что я пробовал это раньше, думаю, сейчас у меня в голове беспорядок, мне нужно очистить свой разум, но спасибо 2 ^ 0 должно быть 1, о шл, да, я пытался поиграть с этим создал также систему, которая проверяет, следует ли ставить 0 в VGAPlate, это не работает, я думаю, я найду способ ее работы, Спасибо, Fuz!   -  person Erik Gelfat    schedule 22.01.2020
comment
@ErikGelfat С удовольствием! Пожалуйста, опишите свои выводы в качестве ответа на свой вопрос, чтобы другие, у кого возникла такая же проблема, могли извлечь выгоду из найденного нами решения.   -  person fuz    schedule 22.01.2020
comment
@fuz done, я думаю, SHL не работает, потому что 0 умножить на 2 равно 0, а не 1, и 2 умножить на два равно 4, а не два, поэтому я думаю, что числа слишком малы для использования сдвига в качестве функции мощности   -  person Erik Gelfat    schedule 22.01.2020
comment
@ErikGelfat Вы сдвигаете 1 влево, а не 0. 1 сдвиг влево на 0 позиций равен 1, сдвиг на 1 место равен 2, сдвиг на 2 места равен 4 и так далее.   -  person fuz    schedule 22.01.2020


Ответы (1)


Спасибо Fuz за то, что он нашел ответ, и Джонатону Рейнхарту за то, что он разъяснил мой вопрос. в процедуре VGAPlaneSelect все значения, которые являются выходными для VGA-адреса 0x3c5, должны быть 2 ^ (плоскость, которую вы хотите выбрать), а для плоскости 0 2 ^ 0 это должно быть 1, и я написал 0

so:

        cmp [VGAPlane], 0
        jne VGAPlaneSelect_0
            mov al, 1h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_0:

лучший способ выполнить VGAPlaneSelect процедуру:

    proc VGAPlaneSelect
        push ax
        push dx
        push cx
        mov al, 02h
        mov dx, 03C4h
        out dx, al
        VGAPlaneSelect_start:
        mov ax, 1
        mov cl, [VGAPlane]
        shl ax, cl
        cmp [VGAPlane], 4
        jne VGAPlaneSelect_end
            mov [VGAPlane], 0
            jmp VGAPlaneSelect_start
        VGAPlaneSelect_end:
        mov dx, 03C5h
        out dx, al
        pop cx
        pop dx
        pop ax
        ret
    endp VGAPlaneSelect
person Erik Gelfat    schedule 22.01.2020
comment
И это в любом случае слишком сложно. Используйте сдвиг с переменным счетом, как предложил fuz. Или самый эффективный способ превратить n в 2^n, если у вас есть 386-совместимый, - это movzx dx, byte [VGAPlane]; xor ax, ax; bts ax, dx. Вам не важен результат FLAGS, только ax |= 1<<dx часть. (Вы можете выбрать любой регистр, и он игнорирует высокий мусор, поэтому вы можете загружать только в DL вместо расширения нулями в DX или EDX, но затем все равно читать DX с помощью BTS.) - person Peter Cordes; 23.01.2020
comment
@PeterCordes Привет, правда, я использую .286, но у меня он работает с SHL - person Erik Gelfat; 23.01.2020
comment
@PeterCordes, дело в том, что он не работает идеально, исходный ответ также, каждое растровое изображение, которое я пытаюсь распечатать с шестого до 21-го пикселя, плоскость 0 испорчена, после того, как эти пиксели 5 пикселей работают отлично, то то же самое и так на, это очень странно, потому что если я печатаю с нулевого пикселя, все печатается отлично - person Erik Gelfat; 23.01.2020
comment
@PeterCordes nvm понял - person Erik Gelfat; 23.01.2020
comment
Ваш обновленный код, использующий сдвиг, все еще сильно усложнен! Похоже, вам просто нужно ограничить счетчик сдвигов до 0..3. Вы можете сделать это перед сдвигом, и вы можете cmp cl, 4 вместо того, чтобы снова проверять память и повторять сдвиг. Или вы могли бы просто mov cl, [VGAPlane]; mov ax, 1; and cl, 3 (маскировать старшие биты); shl ax, cl, если вам действительно не нужно сбрасывать значение в памяти. - person Peter Cordes; 24.01.2020