Форум программистов, компьютерный форум, киберфорум
Assembler: DOS/Real Mode/16-bits
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.55/40: Рейтинг темы: голосов - 40, средняя оценка - 4.55
1 / 1 / 0
Регистрация: 11.10.2016
Сообщений: 13

Вывод текста по точкам напрямую в видеопамять в графическом режиме

24.09.2017, 15:26. Показов 7784. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Написал такую программу для вывода с помощью битовых карт текста. Не могли бы подсказать, в чём ошибка?
При запуске чёрный экран с постоянно движущимися полосами.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
.model small
.386
.stack 100h
data segment 
      fio db 'Hello',0
      coordX dw 0
      coordY dw 0
      widthEc equ 640
data ends
code segment
assume CS:code,DS:data
begin:  mov AX, offset data
        mov DS,AX
        mov AX, 0A000h
        mov ES,AX
        mov AX,0F000h
        mov GS,AX
        lea BX,fio
        ;УСТАНОВКА ВИДОРЕЖИМА
        mov AH,00h
        mov Al,12h
        int 10h
read:   movzx SI,byte ptr [BX]      
        lea ESI,[0FA6Eh+ESI*8]
        mov CX,8
a:      xor DI,DI
        mov DI,coordX
        mov AX,widthEc
        mul coordY
        add DI,AX
        movs byte ptr ES:[DI],GS:[SI]
        inc coordY
        loop a
        inc coordX
        inc BX
        cmp byte ptr [BX],0
        jne read 
exit:   mov AH,00h
        mov AL,03h
        int 10h
        mov AX,4C00h
        int 21h
code ends
        end begin
Добавлено через 26 минут
Assembler
1
mov AX, data
Нашёл ошибку. Только даже при пошаговой отладке через дебагер не заходит дальше первой строки.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
24.09.2017, 15:26
Ответы с готовыми решениями:

Вывод текста в графическом режиме
Есть ли у кого нибудь функция для моментального вывода букв и цифр на экран , и занесения значения в переменную при нажатии enter и...

вывод текста в графическом режиме
Помогите пожалуйста не правильно выводит текст вот эта процедура: void wiwod_texta(char b,int x,int y) { int n=strlen(b); ...

Вывод текста в графическом режиме
можете подсказать пожалуйста как можно вывести текст в графическом моде

16
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4494 / 1669
Регистрация: 01.02.2015
Сообщений: 13,905
Записей в блоге: 12
24.09.2017, 17:25
Потому, что вы программируете 16-разрядное приложение, в котором нет и не может быть 32-разрядных регистров (esi).
Да и GS можно не трогать.

Добавлено через 1 минуту
Если хотите использовать расширенный набор команд - разместите .386 не во 2-й строке, а после объявления сегмента кода.
0
1 / 1 / 0
Регистрация: 11.10.2016
Сообщений: 13
24.09.2017, 17:29  [ТС]
Уже переделал на вот такой вариант. Всё равно выводит не то, что нужно
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
.model tiny
org 100h
.code
.386 
      widthEc equ 639
begin:  
        mov AX,12h
        int 10h
        mov AH,05h
        mov AL,0h
        int 10h
        push 0A000h
        pop ES
        push 0F000h
        pop DS
        lea BX,fio
        ;УСТАНОВКА ВИДОРЕЖИМА
read:   movzx SI,byte ptr [BX]      
        lea ESI,[0FA6Eh+ESI*8]
        mov CX,8
a:      xor DI,DI
        mov DI,coordX
        mov AX,widthEc
        mul coordY
        add DI,AX 
        movs byte ptr ES:[DI],DS:[SI]
        add coordY,1
        loop a
        add coordX,1
        inc BX
        cmp byte ptr [BX],0
        jnz read 
exit:
        mov AH,00h
        mov AL,0
        int 16h
    ;   mov AH,00h
        mov AL,03h
        int 10h
        mov AX,4C00h
        int 21h
         
        fio db "Tarasov Artem",0
        coordX dw 0
        coordY dw 0
code ends
        end begin
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4494 / 1669
Регистрация: 01.02.2015
Сообщений: 13,905
Записей в блоге: 12
24.09.2017, 17:34
Не полностью
Цитата Сообщение от ФедосеевПавел Посмотреть сообщение
Потому, что вы программируете 16-разрядное приложение, в котором нет и не может быть 32-разрядных регистров (esi).
0
1 / 1 / 0
Регистрация: 11.10.2016
Сообщений: 13
24.09.2017, 17:41  [ТС]
Я понимаю, но чем заменить ESI?
Если использовать SI, то будет illegal indexes mode . Или SI + byte ptr?
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4494 / 1669
Регистрация: 01.02.2015
Сообщений: 13,905
Записей в блоге: 12
24.09.2017, 17:55
Я не понимаю сути вычислений. Но заменить можно
Assembler
1
2
3
4
    shl si, 1
    shl si, 1
    shl si, 1
    add si, 0FA6Eh
0
1 / 1 / 0
Регистрация: 11.10.2016
Сообщений: 13
24.09.2017, 18:16  [ТС]
Заменил. Выводить по прежнему не выводит. Необходимо искать проблему именно в логике программы?
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4494 / 1669
Регистрация: 01.02.2015
Сообщений: 13,905
Записей в блоге: 12
24.09.2017, 18:30
Видимо, да.
0
Прощай, Мир!
 Аватар для proc3nt
1673 / 831 / 253
Регистрация: 26.05.2012
Сообщений: 3,056
25.09.2017, 01:22
Цитата Сообщение от Katzer Посмотреть сообщение
mov AX, 0A000h
mov ES,AX
Цитата Сообщение от Katzer Посмотреть сообщение
push 0A000h
pop ES
;устанавливается базовый адрес сегмента видеостраницы для графического видеорежима

Цитата Сообщение от Katzer Посмотреть сообщение
fio db 'Hello',0
Цитата Сообщение от Katzer Посмотреть сообщение
fio db "Tarasov Artem",0
строки объявлены и инициализированы вроде для текстового видеорежима..

Цитата Сообщение от Katzer Посмотреть сообщение
;УСТАНОВКА ВИДОРЕЖИМА
собственно какой режим собираешься программировать: текстовый или графический!?

Цитата Сообщение от Katzer Посмотреть сообщение
с помощью битовых карт
такого вроде у тебя вообще не предусмотрено.. например, буква H для графического режима задается приблизительно таким образом..
Assembler
1
2
3
4
5
6
7
8
H    db    1,1,0,0,0,0,1,1
           1,1,0,0,0,0,1,1
           1,1,0,0,0,0,1,1
           1,1,1,1,1,1,1,1
           1,1,1,1,1,1,1,1
           1,1,0,0,0,0,1,1
           1,1,0,0,0,0,1,1
           1,1,0,0,0,0,1,1
0
1 / 1 / 0
Регистрация: 11.10.2016
Сообщений: 13
25.09.2017, 05:02  [ТС]
Графический. В процессе переделки комент немного сместился.
Про разницу между одинарными и двойными кавычками не знал, спасибо.
По адресу 0F000:0FA6Eh как раз лежат битовые карты первой половины аски таблицы.
Как я выяснил, у меня получает изначально не тот символ, что необходимо
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4494 / 1669
Регистрация: 01.02.2015
Сообщений: 13,905
Записей в блоге: 12
25.09.2017, 07:29
Я не уверен. Мне кажется, что знакогенератор (битовые маски символов) из памяти видеоадаптера отображаются на основную память. Для получения адреса нужно обращаться к BIOS видеосервиса (int 10h), а не использовать константы так как использование русификатора меняет все адреса. К тому же, меняя содержимое регистров видеоконтроллера, можно отображать знакогенератор на произвольную память.

Добавлено через 8 минут
Попробуйте потренироваться в доступе к таблицам знакогенератора в текстовом режиме - отображать большой символ звёздочками.

Когда-то из любопытства написал программку для сравнения двух файлов шрифтов, а если на входе один файл, то сравнивался он с системным шрифтом. На форуме нашёл и использовал следующий код для получения таблицы знакогенератора
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
PROCEDURE GetCrtFont(VAR Buffer; CharWidth : byte);
type
  PBuffer = ^TBuffer;
  TBuffer = array[0..$FFFE] of byte;
 
var
  FontRam : PBuffer;
VAR
{  Buffer  : PBuffer absolute FontImagePtr;}
  I       : Word;
BEGIN
  FontRam := Ptr(SegB800,$0000);
  if (not CharWidth in [8, 14, 16]) then Exit;
  Port[$3C4] := $02;
  Port[$3C5] := $04;
  Port[$3C4] := $04;
  Port[$3C5] := $07;
  Port[$3CE] := $04;
  Port[$3CF] := $02;
  Port[$3CE] := $05;
  Port[$3CF] := $00;
  Port[$3CE] := $06;
  Port[$3CF] := $0C;
  for I:= 0 to 255 do
    Move(FontRam^[I Shl 5],
         TArrByte0(Buffer)[I * CharWidth],
         CharWidth);
  Port[$3CE] := $06;
  Port[$3CF] := $0E;
  Port[$3CE] := $05;
  Port[$3CF] := $10;
  Port[$3CE] := $04;
  Port[$3CF] := $00;
  Port[$3C4] := $04;
  Port[$3C5] := $03;
  Port[$3C4] := $02;
  Port[$3C5] := $03;
end;
Почему-то у меня тогда не получилось чтение через int 10h.

Добавлено через 9 минут
Вот ещё нашёл. Программа переворачивает символы на экране. Виден доступ к таблице знакогенератора. Для вас тут интересна последовательность доступа к этой таблице
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
{Учебная программа для форума.
 При нажатии на Enter "переворачивает" все символы на экране.
 При повторном нажатии - возвращает всё обратно.}
PROGRAM FontRvrs;
CONST
  {Константы для TypePtr процедуры GetCurrentFontInfo, определяющие,
   на какую таблицу будет указывать Info.CharTablePtr               }
  fiFontTable1F   = $00;      {адрес из INT 1Fh}
  fiFontTable43   = $01;      {адрес из INT 43h}
  fiFontTable8x14 = $02;      {адрес фонтов 8x14}
  fiFontTable8x8Lo= $03;      {адрес фонтов 8x8 коды 00h..7Fh}
  fiFontTable8x8Hi= $04;      {адрес фонтов 8x8 коды 80h..FFh}
  fiFontTable9x14 = $05;      {адрес фонтов 9x14}
  fiFontTable8x16 = $06;      {адрес фонтов 8x16}
  fiFontTable9x16 = $07;      {адрес фонтов 9x16}
TYPE
  {структура для процедуры GetCurrentFontInfo}
  TCurrentFontInfo = RECORD
    BytePerChar  : Word;   {число байтов на символ}
    CharPerRow   : Byte;   {число символов в строке-1}
    CharTablePtr : Pointer;{указатель на таблицу символов}
  END;
  {для "грубого" приведения типов}
  TPtrConvert  = RECORD
                   case Word of
                     0:( P           : Pointer    );
                     1:( Offs,Segm   : Word       );
                     2:( b0,b1,b2,b3 : Byte       );
                     3:( c0,c1,c2,c3 : Char       );
                 END;
  TArrByte0    = array [0..0] of Byte;
  TArrWord0    = array [0..0] of Word;
VAR
  {область памяти BIOS}
  {EGA/VGA} {высота матрицы, задающей изображение символа на экране}
  CRT_Points    : Word absolute $0040:$0085;
 
{получение информации о текущем шрифте}
PROCEDURE GetCurrentFontInfo(TypePtr:Byte; VAR Info : TCurrentFontInfo);
assembler;
asm
  push es
  mov  bh,TypePtr
  cmp  bh,fiFontTable9x16
  jbe  @@Ok
  push si
  xor  ax,ax
  les  si,Info
  mov  TCurrentFontInfo(es:[si]).BytePerChar ,ax
  mov  TCurrentFontInfo(es:[si]).CharPerRow  ,al
  mov  TPtrConvert(TCurrentFontInfo(es:[si]).CharTablePtr).Offs,ax
  mov  TPtrConvert(TCurrentFontInfo(es:[si]).CharTablePtr).Segm,ax
  pop  si
  jmp  @@EndOfProc
@@Ok:
  push bp
  mov  ax,1130h  {int 10h, функция 11h, подфункция 30h}
{  mov  bh,TypePtr}
  int  10h
  mov  ax,es
  mov  bx,bp
  pop  bp
  push si
  les  si,Info
  mov  TCurrentFontInfo(es:[si]).BytePerChar ,cx
  mov  TCurrentFontInfo(es:[si]).CharPerRow  ,dl
  mov  TPtrConvert(TCurrentFontInfo(es:[si]).CharTablePtr).Offs,bx
  mov  TPtrConvert(TCurrentFontInfo(es:[si]).CharTablePtr).Segm,ax
  pop  si
@@EndOfProc:
  pop  es
END;
 
PROCEDURE SetUserFontEnh(VAR CharTable;    FirstChar:Char;
                             NumChar:Word; BytePerChar,NBlock :Byte);
assembler;
asm
  push es
  push bp
  mov  ax,1110h {int 10h, функция 11h, подфункция 10h}
  xor  dh,dh
  mov  dl,FirstChar
  mov  cx,NumChar
  mov  bh,BytePerChar  {8,14,16}
  mov  bl,NBlock       {0..4}
  les  si,CharTable
  mov  bp,si
  int  10h
  pop  bp
  pop  es
end;
 
{переворачивание одного символа}
PROCEDURE GlyphReverse(VAR Glyph;                {массив с описанием символа}
                           GlyphHight,           {высота символа}
                           GlyphWidth : Integer);{ширина символа}
VAR
  i     : Integer;
  b     : Byte;
  w     : Word;
BEGIN
  Dec(GlyphHight);
 
  for i:=0 to (GlyphHight div 2) do begin
    if GlyphWidth=1
    then begin
      b:=TArrByte0(Glyph)[i];
      TArrByte0(Glyph)[i]:=TArrByte0(Glyph)[GlyphHight-i];
      TArrByte0(Glyph)[GlyphHight-i]:=b;
    end
    else begin
      w:=TArrWord0(Glyph)[i];
      TArrWord0(Glyph)[i]:=TArrWord0(Glyph)[GlyphHight-i];
      TArrWord0(Glyph)[GlyphHight-i]:=w;
    end;
  end;
END;
 
PROCEDURE FontReverse;
VAR
  FontWsys,               {ширина символа в точках}
  FontHsys,               {высота в строках/байтах}
  FontRsys,               {ширина в байтах        }
  FontSsys      : Integer;{число байтов на символ }
 
  FontInfo      : TCurrentFontInfo;
 
  i             : Integer;
  b             : Byte;
  w             : Word;
 
  NumFontTable  : Byte;
BEGIN
  {получение информации о текущем шрифте}
  { - из процедуры}
  GetCurrentFontInfo(fiFontTable8x8Lo, FontInfo);
  FontSsys:=FontInfo.BytePerChar;     {число байтов на символ}
  { - из области данных BIOS}
  FontHsys:=CRT_Points;               {высота в строках/байтах}
  {вычисление недостающих параметров текущего шрифта}
  FontRsys:=FontSsys div FontHsys;    {ширина в байтах        }
  if FontRsys=1
    then FontWsys:=8
    else FontWsys:=9;
  {получение правильного указателя на таблицу знакогенератора}
  case FontSsys of
     8: NumFontTable:=fiFontTable8x8Lo; {шрифт 8x8}
    14: NumFontTable:=fiFontTable8x14;  {шрифт 8x14}
    16: NumFontTable:=fiFontTable8x16;  {шрифт 8x16}
    28: NumFontTable:=fiFontTable9x14;  {шрифт 9x14}
    32: NumFontTable:=fiFontTable9x16;  {шрифт 9x16}
  end;
  GetCurrentFontInfo(NumFontTable, FontInfo);
  {  WriteLn('Шрифт ', FontWsys, 'x', FontHsys);}
 
  {перевернуть все символы шрифта}
  for i:=$00 to $FF do {по символам}
    GlyphReverse(TArrByte0(FontInfo.CharTablePtr^)[i*FontSsys], FontHsys, FontRsys);
  {задействовать изменения}
  SetUserFontEnh(FontInfo.CharTablePtr^, #0, 255, FontSsys, 0);
END;
 
VAR
  c     : Char;
BEGIN
  WriteLn('----------------------------------------------------------');
  WriteLn('Программа для демонстрации работы со знакогенератором VGA.');
  WriteLn('Изображене каждого символа "переворачивается".');
  WriteLn('----------------------------------------------------------');
  WriteLn('Пробный вывод таблицы символов:');
  for c:=#$20 to #$FF do begin
    Write(c);
    if (Ord(c) AND $0F = $0F) then WriteLn;
  end;
  Write('Для "переворачивания" символов нажмите Enter...');
  ReadLn;
  FontReverse;
  Write('Для "переворачивания" символов нажмите Enter...');
  ReadLn;
  FontReverse;
END.
0
1 / 1 / 0
Регистрация: 11.10.2016
Сообщений: 13
25.09.2017, 07:49  [ТС]
То есть использование англ.версии win98 решит проблему?
Да, вы правы. аски код.заглавной А меняется на 01h или 02h.
Хотя, такое преобразование происходит для любого символа.
Нужна функция 1102h,которая вернет адрес как раз таки шрифта 8х8?
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4494 / 1669
Регистрация: 01.02.2015
Сообщений: 13,905
Записей в блоге: 12
25.09.2017, 09:03
Сейчас тороплюсь и не сверяю назначение функций. Во второй программе я использовал GetCurrentFontInfo - 1130h. Получал указатель на требуемую таблицу знакогенератора. А за 1102h сейчас ничего не могу сказать.
0
Эксперт Hardware
Эксперт Hardware
 Аватар для R71MT
6211 / 2445 / 403
Регистрация: 29.07.2014
Сообщений: 3,175
Записей в блоге: 4
25.09.2017, 12:30
Лучший ответ Сообщение было отмечено Katzer как решение

Решение

Цитата Сообщение от Katzer Посмотреть сообщение
Нужна функция 1102h,которая вернет адрес как раз таки шрифта 8х8? По адресу 0F000:0FA6Eh как раз лежат битовые карты первой половины аски таблицы.
эта функция(1102h) устанавливает шрифт 8х8 для текстового режима и к твоей задаче отношения не имеет. В графическом режиме свои шрифты и функции для них начинаются с 1120h. При установки в\режима шрифты копируются из VGA-ROM в банк(2) видеопамяти и дальше читаются уже от туда. Адрес расположения хранится в векторе(43h) таблицы прерываний:

Code
1
2
3
4
5
 
INT 43 - СИМВОЛЬНАЯ ТАБЛИЦА (EGA,MCGA,VGA)
------------------------------------------
Адрес образа символов 00h-7Fh текущего графического шрифта.
Это - не вызываемый вектор!
Ключевое слово здесь - не вызываемый вектор! Значит его нужно читать или напрямую с таблицы векторов, или получить чз функцию видеосервиса(1130h) с BH=1 - получить инфу о графическом шрифте:

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
INT-10h. AX = 1130h. Получить информацию о шрифте.
--------------------------------------------------
Вход:  BH = 0 - адрес графического шрифта через int-1Fh
            1 - адрес графического шрифта через int-43h
            2 - адрес шрифта 8х14
            3 - адрес шрифта 8х8  (младшие 128 символов) 
            4 - адрес шрифта 8х8  (старшие 128 символов)
            5 - адрес шрифта 9х14
            6 - адрес шрифта 8х16
            7 - адрес шрифта 9х16 (толька VGA+)
 
Выход:  ES:BР - указывают на образы запрашиваемого шрифта в памяти
           CX - байт на знак в текущем шрифте
           DL - всего информационных строк на экране
------
PS\\ значение СХ равно полю 0:485h
К примеру, я оттрасировал такой код и получил в ES:BP вектор 43h, где и находятся образы графических шрифтов. Здесь видно, что они валяются по адресу [C000:3015h]:

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
;fasm-code 
;---------
org 100h
    mov    ax,12h     ; ставим режим
    int    10h 
 
    mov    ax,1130h   ; информация о шрифте
    mov    bh,1       ; 1 = адрес графического шрифта чз INT-43h
    int    10h        ; ---------------
ret                   ; Выход: cx = 10h - 16 строк растра в символе,
                      ;        dl = 1Dh - 29 знакоряда (инфо строк) в окне,
                      ;     es:bp = C000:3015 - адрес образов шрифта 9х16.
Проверяем..
Это-же значение должно лежать и таблице векторов: 43h * 4 = 010Ch
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
C:\>debug
-d 0:10C
0000:0100                                        15 30 00 C0               .0..
0000:0110  8A ED 00 F0 8A ED 00 F0 - 50 00 97 F1 8A ED 00 F0   ........P.......
0000:0120  8A ED 00 F0 8A ED 00 F0 - 8A ED 00 F0 8A ED 00 F0   ................
0000:0130  8A ED 00 F0 8A ED 00 F0 - 8A ED 00 F0 8A ED 00 F0   ................
0000:0140  8A ED 00 F0 8A ED 00 F0 - 8A ED 00 F0 8A ED 00 F0   ................
0000:0150  8A ED 00 F0 8A ED 00 F0 - 8A ED 00 F0 8A ED 00 F0   ................
0000:0160  8A ED 00 F0 8A ED 00 F0 - 8A ED 00 F0 8A ED 00 F0   ................
0000:0170  04 07 7E D3 8A ED 00 F0 - 8A ED 00 F0 8A ED 00 F0   ..~.............
0000:0180  00 00 00 00 00 00 00 00 - 00 00 00 00               ............
-
-d С000:3015
C000:3010                 00 00 00 - 00 00 00 00 00 00 00 00        ...........
C000:3020  00 00 00 00 00 00 00 7E - 81 A5 81 81 A5 99 81 81   .......~........
C000:3030  7E 00 00 00 00 00 00 7E - FF DB FF FF DB E7 FF FF   ~......~........
C000:3040  7E 00 00 00 00 00 00 00 - 00 6C FE FE FE FE 7C 38   ~........l....|8
C000:3050  10 00 00 00 00 00 00 00 - 00 10 38 7C FE 7C 38 10   ..........8|.|8.
C000:3060  00 00 00 00 00 00 00 00 - 18 3C 3C E7 E7 E7 18 18   .........<<.....
C000:3070  3C 00 00 00 00 00 00 00 - 18 3C 7E FF FF 7E 18 18   <........<~..~..
C000:3080  3C 00 00 00 00 00 00 00 - 00 00 00 18 3C 3C 18 00   <...........<<..
C000:3090  00 00 00 00 00                                    .....
-
Пройдя в отладчике по указанному адресу [C000:3015h] можно увидеть образы графических шрифтов. Но это только начало. Функция(1130h) вернула в СХ значение 10h, значит в одном символе 16-строк, т.е. один символ кодируется 16-ю байтами и размер его 9х16. Графически это выглядит так:



Вывод на экран в граф\режиме осуществляется построчно (ширина 1-ой строки = 1 пиксель), и если шрифт 9х16, то значит каждый образ символа ты должен прочитать 16-раз! То есть сначала первую строку (всех символов выводимой строки), потом вторую строку, и т.д. Чтобы выбрать из образов, какой именно символ будешь выводить, нужно к базе(3015h) прибавлять порядковый номер символа, например так:

Assembler
1
2
     mov   bx,3015h         ; база
     mov   si,byte[bx+'T']  ; берём из образов первый байт символа 'T'.
Удобно сначала скопировать все образы выводимой строки в свой буфер, и выводить на экран уже подготовненные образы строки. Это исключит вложенные циклы, которые сильно тормозят весь процесс.

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fio   db  'Tarasov Artem'
len   =   $ - fio          ; длина строки
buff  db  16*len dup(0)    ; буфер под образы (16-байт на символ)
 
;----------------
     push  0C000h
     pop   ds
     mov   dx,len            ; длина строки
     mov   bx,fio            ; её адрес
     mov   di,buff           ; приёмник
     mov   si,3015h          ; база 
     xor   ax,ax
@1:  mov   al,byte[es:bx]    ; читаем очередной символ из 'fio'
     inc   bx                ;        (сл.символ..)
     push  si                ; запомнить базу!
     add   si,ax             ; получаем адрес образа символа
     mov   cx,16             ; длина образа
     rep   movsb             ; копируем очередной образ (16-байт)
     pop   si                ; базу на место
     dec   dx                ; все образы скопировали?
     jnz   @1                ; нет..
Теперь у тебя в буфере все образы.. Если не полениться, то можно было сразу расположить байты образов в нужном порядке, чтобы не прыгать при выводе. - т.е. копировать из базы каждый\16-ый байт.

Именно этим занимается знакогенератор адаптера при выводе символов на экран в графическом режиме. Геморно это\всё делать вручную и не понимаю, зачем это тебе нужно. Проще выставить графический режим и просто вызвать функцию вывода строки DOS - 09h. Она автоматизирует этот процесс сама.

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
;fasm-code 
;----------
org  100h
jmp  start
 
fio   db  'Tarasov Artem'
 
start: mov  ax,12h
       int  10h 
 
       mov  ah,9
       mov  dx,fio 
       int  21h
 
       xor  ax,ax 
       int  16h
       mov  ax,3
       int  10h
       ret
Миниатюры
Вывод текста по точкам напрямую в видеопамять в графическом режиме  
3
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4494 / 1669
Регистрация: 01.02.2015
Сообщений: 13,905
Записей в блоге: 12
25.09.2017, 18:41
К такому шикарному пояснению добавлю ремарку.

Таблицы знакогенераторов:
Int 1Fh - указывает на таблицу знакогенератора для ASCII кодов 80h-FFh в CGA-сопоставимых графических модах 4-6 (только 8x8);
Int 43h - указывает на таблицу знакогенератора для ASCII кодов 00h-FFh в EGA/VGA графических режимах. Причём, размер глифа задаётся пользователем. А при установке этого шрифта ещё и выбирается число текстовых строк на экране (напомню, что это в графическом режиме).

Эти таблицы используются для вывода символов средствами BIOS в графических режимах.

Но у топикстартера задача вывести символы попиксельно (по крайней мере именно так я понял). Поэтому, какую таблицу он "урвёт", такой и будет шрифт.
Т.е. ему достаточно "дотянуться" до любой из таблиц, правильно интерпретировать размеры глифов (символов) и вывести их на экран. Эти таблицы уже присутствуют в ROM BIOS, в крайнем случае их в RAM размещает русификатор - т.е. их не нужно устанавливать.

Добавлено через 3 часа 55 минут
Сделал с выводом каждой точки через функции BIOS (т.е. медленно). Но лично мне было любопытно "дотянуться" до таблиц знакогенератора.
Не соображу почему шрифт получился таким крупным. Возможно, из-за выбранного видеорежима.

Сам алгоритм простой - вызвал Get EGA information (int 10h ax=1130h) с выбранным шрифтом (наугад взял 8x14). Получил указатель на знакогенератор. Потом просто - по символу из выводимой строки получаю смещение в знакогенераторе до глифа (код символа * размер глифа), а потом вывожу битовое изображение глифа.

Никогда не интересовался графикой, поэтому не понимаю, как напрямую выводить точки в память. Поэтому вывожу через видеосервис.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
.model small
 
.stack 100h
 
.data
        CrLf            db      0Dh, 0Ah, '$'
        azMsg           db      'My Little String!', 0
 
        Mode0D_W        equ     320     ;ширина экрана в пикселях для видеорежима 0Dh
        Mode0D_H        equ     200     ;высота экрана в пикселях для видеорежима 0Dh
        Mode0D_C        equ     16      ;количество цветов для видеорежима 0Dh
        Mode0D_A        equ     0A000h  ;начальный адрес видеопамяти для видеорежима 0Dh
 
        lpFontTable8x14 dw      2 dup(?);указатель на таблицу символов 8x14
        FontH           equ     14      ;количество строк в описании глифа
 
        Xstart          dw      100     ;координаты начала надписи
        Ystart          dw      70
 
        Xcurr           dw      ?       ;текущие координаты
        Ycurr           dw      ?
 
        Color           db      3       ;цвет выводимого текста
 
.code
 
main    proc
        mov     ax,     @data
        mov     ds,     ax
 
        ; установка графического видео режима
        mov     ax,     000Dh
        int     10h
 
        ;возьмём какую-нибудь таблицу знакогенератора
        ;например, 8x14
 
        ;Get EGA information
        mov     ax,     1130h
        mov     bh,     2       ;2 = return ES:BP => ROM 8x14 font table addr
        int     10h
        mov     lpFontTable8x14, bp
        mov     lpFontTable8x14+2, es
 
        mov     ax,     Xstart
        mov     Xcurr,  ax
        mov     ax,     Ystart
        mov     Ycurr,  ax
        lea     si,     azMsg
        cld
ForByChar:
        lodsb                   ;al - очередной символ строки
        or      al,     al      ;конец строки? - прервать цикл
        jz      Break
 
        mov     cx,     FontH   ;цикл по строкам глифа
        mul     cl              ;di=(код символа)*(размер глифа) - смещение строки текущего глифа
        mov     di,     ax
ForByLines:
        push    ax
        push    cx
 
        mov     ah,     es:[bp+di]      ;считываем очередную строку глифа
        mov     cx,     8
ForByBits:
        mov     al,     0       ;сдвигаем биты влево, и выбираем цвет точки
        shl     ah,     1
        sbb     al,     0       ;если бит был равен 0 - то al:=0
        and     al,     Color   ;если бит был равен 1 - то al:=Color
 
        push    ax
        push    bx
        push    cx
        push    dx
        ;установка графической точки
        mov     ah,     0Ch
        mov     bh,     0       ;номер видеостраницы
        mov     dx,     Ycurr   ;строка
        mov     cx,     Xcurr   ;колонка
        ;mov    al,     1       ;цвет (+80h означает XOR с точкой на экране)
        int     10h
        pop     dx
        pop     cx
        pop     bx
        pop     ax
 
        inc     word ptr [Xcurr]        ;следующую точку выводить правее
        loop    ForByBits
 
        ;сместиться на одну строку вниз при выводе следующей линии глифа
        inc     word ptr [Ycurr]
        ;вернуться на начальную колонку при выводе след. линии глифа
        sub     [Xcurr],word ptr 8
        pop     cx
        pop     ax
        add     di,     1       ;переходим к рассмотрению следующей строки глифа
        loop    ForByLines
 
        ;для вывода глифа следующего символа
        ; - уменьшить строку на высоту глифа
        sub     [Ycurr],word ptr FontH
        ; - сдвинуть колонку на ширину глифа
        add     [Xcurr],word ptr 8
        jmp     ForByChar
Break:
        ;ожидание нажатия любой клавиши
        mov     ah,     08h
        int     21h
        ;переключение в текстовый режим
        mov     ax,     0003h
        int     10h
        ;завершение программы
        mov     ax,     4C00h
        int     21h
main    endp
 
end     main
0
1 / 1 / 0
Регистрация: 11.10.2016
Сообщений: 13
25.09.2017, 22:46  [ТС]
Спасибо вам всем огромное за вашу отзывчивость и столь полезные и обширные объяснения!

Добавлено через 1 минуту
Я бы использовал прерывание БИОСА, но препод требует использовать именно запись напрямую в видеопамять. И делай что хочешь с этим.
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8659 / 4494 / 1669
Регистрация: 01.02.2015
Сообщений: 13,905
Записей в блоге: 12
25.09.2017, 22:50
Это особенность любого форума - часто решения не полные, что-то приходится "допиливать".
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
25.09.2017, 22:50
Помогаю со студенческими работами здесь

Вывод текста в графическом режиме
Покажите пожалуйста как вывести в графическом режиме текст, чтобы было красиво:). Мне нужно вывести фамилию Петров

Вывод текста в графическом режиме (tasm)
собственно весь вопрос: как выводить текст в графическом режиме

Вывод цветного текста в графическом режиме
Помогите написать задачку) Юзаю PascalABC)) Суть: Вводится слово. Вывести гласные буквы слова красным цветом, а звонкие и глухие...

Вывод текста в графическом режиме (оптимизация)
Пытаюсь оптимизировать свой набросок для вывода текста в видеорежиме VESA 1280x1024 119h. Визуально все работает, но сравнительно медленно....

турбо паскаль(вывод текста в графическом режиме)
как вывести текст в графическом режиме знаю есть процедура settextstyle и outtextxy ну чтото не получается никак (((0


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru