Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Низкоуровневое программирование для дZенствующих (FAQ) #3


Служба Рассылок Subscribe.Ru проекта Citycat.Ru

НИЗКОУРОВНЕВОЕ ПРОГРАММИРОВАНИЕ ДЛЯ ДZЕНСТВУЮЩИХ (FAQ)
АРХИВ MAIL-КОНФЕРЕНЦИИ RTFM_HELPERS ЗА МАРТ 2001

Сайт: http://hi-tech.nsys.by/
Информация о конференции: http://hi-tech.nsys.by/forum/
ИО модератора aka DZ Kir777: kir777@hotmail.com
Co-moderator aka Serrgio: serrgio@gorki.unibel.by


                        [В О П Р О С - О Т В Е Т]

=======================================================================

ВОПРОС:   Есть указатель на массив битов килобайт на 4-5.Размер
          массива кратен 32 битам. Нужно с некой позиции внутри
          сдвинуть вправо ровно на 1 бит с потерей последнего бита.

ХЕМУЛЬ:   Написано с ходу, без проверки.

          ; In: DS:SI - source address
          ; CX - block size (any alignment, but >1)
          ; Out: none
          ; Modf: CX, SI

          shr cx,1
          jnc @@bigshrloop
          shr byte ptr [si]
          inc si
          @@bigshrloop: rcr word ptr [si]
          inc si
          inc si
          loop @@bigshrloop

          Выбран простейший, кратчайший вариант без оптимизаций по
          скорости, как то:
          - развёртка цикла,
          - использование 32-битных инструкций,
          - выравнивание SI перед циклом на word/dword.

          Для небольших блоков в несколько слов затраты на код по
          выравниванию будут больше, чем данный цикл. Если
          предположить, что CX всегда кратен 2, то код можно сократить
          следующим образом:

          shr cx,1
          @@bigshrloop: rcr word ptr [si]
          inc si
          inc si
          loop @@bigshrloop

          Если предположить, что CX заранее указывает количество слов,
          а не байт, то первый shr следует заменить на clc.

          P.S. Обрати внимание: здесь используется то свойство inc,
          что эта инструкция не трогает флаг переноса.

-----------------------------------------------------------------------

ВОПРОС:   Скажите, как можно вывести 1 пиксель на экран в режиме
          320x(Что-то_там)x(256 цветов)


ХЕМУЛЬ:   mov ax,13h ; set 13h (320x200, 256 colors) video mode
          int 10h
          mov ah,0Ch ; function #
          mov al,0Fh ; white color
          mov bh,0 ; video page #
          mov cx,160 ; X
          mov dx,100 ; Y
          int 10h

          Способ довольно медленный (_поточечное_ рисование прямым
          обращением к видеопамяти на порядок быстрее) - но очень
          простой, универсальный и для случая пары-другой точек
          вполне подходящий.

          Для случая прямого рисования в видеопамяти нужно знать
          начальный адрес (для 13h - это 0A000h:0) и организацию
          видеопамяти (для 13h на каждый пиксел отводится байт).
          Также нужно знать цветовую палитру, если пользуешься
          стандартной (для 13h 0-0Fh - стандартные цвета CGA, 10h-1Fh
          - градации серого с увеличивающейся интенсивностью, дальше
          идут 216 цветов в трёх группах с уменьшающейся
          интенсивностью, каждая из которых делится на три группы с
          уменьшающейся насыщенностью, каждая из которых содержит 24
          цвета с переходом цветности от синего через красный к
          зелёному). Ниже я привожу маленькую прожку, демонстрирующую
          палитру через прямое рисование в памяти:

          ________O\_/_________________________________\_/O__________
          #include <cv/asm86.h>
          #include <cv/types.h>

          #pragma option -N-

          void NSMALL_ drawstripe(word y, word len, word color){
          for(y = y*320u + 40; len; len--, y += 10, color++){
          byte far *p = (byte far*)MK_FP(0xA000, y);
          for(word j = 0; j < 10; j++, p += 320)
          for(word i = 0; i < 10; i++) p[i] = color;
          } }

          void main(){
          _AX = 0x13; I int 10h;
          drawstripe(40, 16, 0);
          drawstripe(52, 16, 16);

          word color = 32, y = 64;
          while(y < 160){
          drawstripe(y, 24, color); y += 10, color += 24;
          drawstripe(y, 24, color); y += 10, color += 24;
          drawstripe(y, 24, color); y += 12, color += 24;
          }

          drawstripe(y, 256-216-32, 216+32);
          _AH = 0; I int 16h; _AX = 3; I int 10h;
          }
          _______________________________________________________
          O/~\ /~\O

          Если же тебе нужно более серьёзные познания в графике, то
          используй соответствующую документацию. Например, могу
          порекомендовать Programmers Guide to PC and PS/2 Video
          Systems от Ричарда Вилтона.

-----------------------------------------------------------------------

ВОПРОС:   Не подскажете ли функцию сдвига видеостраницы на пиксель
          вправо?

MIXER:    Я думаю тебе полезно будет знать это:
          INT 10h, функция 4fh, подфункция 02h: установить видеорежим
          с заданным номером.
          Отличие от простого 10h в том, что это функция VESA, а
          преимущества в ряде дополнительных возможностей.
          Функция устанавливает видеорежим с заданным номером и режим
          адресации видеопамяти.
           AX = 4F02h
           BX = код видеорежима
          Он (код) имеет следующий формат:
          Биты Значение
          0-8 Номер режима (если 8-й бит = 0, то это режим
          производителя видеоконтроллера, если 1 - VESA режим)
          9-13 Зарезервированы
          14 0 - страничный режим адресации видеопамяти(память
          сегментируется по 64К),
          1 - линейный.
          15 0 - очищать видеопамять при переключении режимов, 1- не
          переключать
          Режимы меньше 100h не считаются VESA и передаются на
          обработку BIOS 10h.
          Приведу основные на мой взгляд режимы:
          Номер режима Разрешение Число цветов Бит на точку
          100h 640x400 256 8
          101h 640x480 256 8
          103h 800x600 256 8
          10Dh 320x200 32K 1:5:5:5
          113h 800x600 32K 1:5:5:5
          INT 10h, функция 4Fh, подфункция 03h: определить код
          текущего видеорежима.
          In: AX = 4F03h
          Out: AX = код возврата BX = код видеорежима.
          ... подфункция 06h: получить или установить длину
          логической строки развертки.
          In: AX = 4F06h
          BL = 0 - установить длину в пикселах, 1 - получить в
          пикселах, 2 - установить в байтах, 3 - получить
          максимально возможную длину в пикселах.
          CX = ширина строки (только для BL=0,2)
          Out: AX = код возврата
          BX = число байт на строку развертки
          CX = число пикселей на строку
          DX = макс. число строк развертки
          ... подфункция 07h: получить или установить координаты
          левого верхнего угла экрана.
          In: AX = 4F07h
          BH = 0
          BL = код операции (00h - установить начало экрана,
          01h - получить начало экрана, 80h - установить начало экрана
          в процессе обратного хода луча по кадру)
          CX = первый отображаемый пиксель на строке развертки
          (при BL = 00,80)
          DX = первая отображаемая строка развертки (при BL = 00,80)
          Out: AX = код возврата
          CX = первый отображаемый пиксель на строке развертки
          (при BL = 01)
          DX = первая отображаемая строка развертки (при BL = 01)
          Надеюсь все это поможет тебе достигнуть чего ты хочешь.
          В частности плавная прокрутка делается последней функцией.

-----------------------------------------------------------------------

ВОПРОС:   Как "переключать" (на assembler) процессор из защищённого
          режима в незащищённый? (надо использовать расширенные
          регистры)


OLEGH:    Переключить процессор из защищенного режима в реальный можно
          командами
          mov eax, cr0
          and eax, NT 1
          mov cr0, eax ,т.е. сбросом бита 0 в управляющем регистре cr0
          (бит управления защищенным режимом). Однако:
          - эти команды работают, только если в защищенном режиме
          процессор имел максимальный текущий уровень
          привилегированности (находился на нулевом кольце защиты).
          В противном случае попытка выйти из защищенного режима
          приводит к генерации исключительной ситуации
          "общее нарушение защиты" (GPF - General Protection Fault);
          - ну и про реинициализацию системы аппаратных прерываний,
          линии A20 и прочей аппаратуры нужно не забыть (если,
          конечно, это необходимо в твоем случае).

-----------------------------------------------------------------------

ВОПРОС:   Как скомпилировать программу использующую регистры eax,edx...

OLEGH:    Перед использованием команд с 32-битными регистрами поставь
          директиву ассемблеру '.386' или 'P386', или '.386p', если
          собираешься использовать инструкции защищенного режима.

-----------------------------------------------------------------------

ВОПРОС:   Как можно получить содержимое регистра IP?

ХЕМУЛЬ:   "mov ax,offset $" загружает в ax адрес данной инструкции.

-----------------------------------------------------------------------

ВОПРОС:   Разъясните кто-нибудь, почему не работает нижеприведенный
          кусок текста на ассемблере из Паскаля? Суть: в регистре AL
          поочередно должны появляться байтики из массива DATA, но там
          появляется все, что угодно, только не они.

          ________________________________________
          Type
          TData = Array [0..255] Of Byte;

          Procedure SendData;
          Var
          Data : TData;
          Begin
          asm
          lds bx, DWORD PTR data
          mov cx, bx
          add cx, 255
          @r:
          mov al, BYTE PTR ds:[bx]
          cmp bx, cx
          je @quit
          inc bx
          jmp @r

          @quit:
          end;
          end;
          ________________________________________

MIXER:    Ты наверное не совсем точно понял значение lds
          (или DWORD PTR). Lds в зависимости от use 16 или use 32
          загружает в приемник (bx) первые два байта источника,
          тобишь data, а остальные 2 в ds, в случае с use 32 все 4
          в приемник. Если бы ты смотрел внимательнее, то ты бы
          увидел, что после lds DWORD PTR Data в bx, ds оказываются
          первые числа массива. Думаю ты уже понял почему. Здесь
          вместо lds нужно вставить mov bx, offset Data, а в ds уже
          нужное значение.

          > mov cx, bx
          > add cx, 255
          >@r:
          > mov al, BYTE PTR ds:[bx]
          BYTE PTR здесь не нужно.

          > cmp bx, cx
          > je @quit
          > inc bx
          > jmp @r

          >@quit:
          > end;
          >end;
          ________________________________________

-----------------------------------------------------------------------

ВОПРОС:   Подскажите пожалуйста, чем отличается nasm от остальных
          ассемблеров?

ХЕМУЛЬ:   1. собственно языком, практически несовместимым с другими
          (NASM, например,нельзя использовать как backend для TP/TC)
          2. доступностью сорсов
          3. бесплатностью

=======================================================================
(С) HI-TECH group. All rights reserved and reversed. Оригинальная
грамматика авторов сохранена.

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться Рейтингуется SpyLog

В избранное