Программирование на ассемблере на высоком, среднем и низком уровне
Несмотря на то что ассемблер является машино-ориентированным языком, т.е. языком низкого уровня, программист может применять его для работы как на высоком (в известном смысле), так и на среднем и низком уровне. •
Примером программы, использующего высокий уровень, является программа HЕLLO. Алгоритм этой программы сводится к подготовке данных, необходимых для вызова функции DOS. Таким образом, к программам, написанным на высоком уровне, можно отнести все те программы, которые используют только функции DOS. Преимуществами этого метода являются простота написания и наглядность исходного текста, недостатком – медленная работа программы (по меркам ассемблера).
Если необходимо повысить скорость выполнения программы в операциях ввода-вывода, можно порекомендовать прямое обращение к функциям BIOS. Например, в той же программе HELLO можно было бы воспользоваться функцией BIOS с номером lOh, осуществляющей вывод на дисплей. Тогда текст процедуры WriteMsg может иметь вид, приведенный на рис.3.4, из которого можно сделать вывод, что размер программы увеличился, а наглядность уменьшилась. Но применение вызова функции BIOS вместо функции DOS дает выигрыш в скорости выполнения программы примерно в 1,07 раза. Размер же выполняемого файла увеличился всего в 1,02 раза. Таким образом, даже в этом весьма простом и далеком от совершенства примере повышение эффективности составило 1,05 раза. Поэтому программирование с применением прямых вызовов функций BIOS, хотя и связано с некоторым неудобством работы, но часто может быть оправдано повышением скорости выполнения программы.
WriteMsg PROC NEAR
mov ВХ, DX
mov АН, OEh
mov ВН, О
Next: mov AL, [ВХ]
crnp AL. '$'
je Quit
int lOh
inc ВХ
jmp next
Quit: ret
WriteMsg ENDP
Рис.3,4. Применение функции BIOS вместо функции DOS.
Низкий уровень программирования на ассемблере подразумевает прямое обращение к каналам ввода-вывода устройств, называемых портами ввода-вывода, и прямой доступ в оперативную память. Смысл применения портов ввода-вывода сводится к следующему. Все внешние устройства, подсоединенные к компьютеру, могут считывать или записывать в специальные ячейки, которые называются портами ввода-вывода, какие-то определенные значения. При выполнении программы процессор также может выполнять операции чтения и записи по отношению к этим портам.
Например, принтеры, присоединяемые к компьютеру по параллельному порту, используют порты ввода-вывода с номерами от 378h до 37Fh. Если принтер присоединен, скажем, к порту LPTI, то для его инициализации необходимо послать в порт ввода-вывода 37Ah значение 12, затем подождать некоторое время и послать в тот же порт значение 8, что и выполняется в следующем фрагменте кода программы командами OUT:
mov DX,37Ah
mov AL, 12
out DX,AL
mov CX.1000
Delay: dec CX
jnz Delay
mov AL, 8
out DX,AL
Для получения информации об ошибке принтера используется порт статуса принтера с номером 379h. Например, значение F7h, полученное из этого порта командой IN, говорит о том, что принтер выключен:
mov DX,379h
in AL.DX
cmp AL,OF7h
je Оuit
Таким образом, программирование на уровне портов Ввода-вывода требует очень хорошего знания принципов работы конкретных устройств, и применение такого метода оправданно только в тех случаях, когда пишется программа для работы с нестандартными устройствами или когда требования к скорости выполнения программы очень высоки.
Кроме прямой работы с портами ввода-вывода, при программировании на низком уровне используется прямое обращение к памяти. Чаще всего это применяется для экранных или дисковых операций. На рис. 3.5 показан вариант реализации процедуры WriteMsg программы HELLO, когда используется прямая запись в видеопамять; начинающуюся с адреса B800h (для цветного дисплея, или BOOOh для монохромного ).
WriteMsg PROC NEAR
mov ВХ, DX
mov AX, OBSOOh
mov ES, AX
mov Dl, 0
mov AH, 7
Next: mov AL, [ВХ]
cmp AL, '$'
je Quit
mov ES: [Dl], AX
add Dl. 2
inc ВХ
jmp Next
Quit: ret
WriteMsg ENDP
Рис. 3.5. Применение прямой записи в память.