Языки ассемблера
Непосредственно на машинном языке в наше время не программирует практически никто. Первый уровень, позволяющий абстрагироваться от схемы кодирования команд, – это уже упоминавшийся язык ассемблера. В языке ассемблера каждой команде машинного языка соответствует мнемоническое обозначение. Все приведенные ранее примеры написаны именно на языке ассемблера, да и в тексте использовались не бинарные коды команд, а их мнемоники.
Встречаются ассемблеры, которые предоставляют мнемонические обозначения для часто используемых групп команд. Большинство таких языков позволяет пользователю вводить свои собственные мнемонические обозначения – так называемые макроопределения или макросы (macros), в том числе и параметризованные (пример 2.7).
Отличие макроопределений от процедур языков высокого уровня в том, что процедура компилируется один раз, и затем ссылки на нее реализуются в виде команд вызова. Макроопределение же реализуется путем подстановки тела макроопределения (с заменой параметров) на место ссылки на него и компиляцией полученного текста. Компиляция ассемблерного текста, таким образом, осуществляется в два или более проходов – на первом осуществляется раскрытие макроопределений, на втором – собственно компиляция, которая, в свою очередь, может состоять из многих проходов, смысл которых мы поймем далее. Часть ассемблера, реализующая первый проход, называется макропроцессором.
Пример 2.7. Пример использования макроопределений:
; Фрагмент драйвера LCD для микроконтроллера PIC ; (с) 1996, Дмитрий Иртегов. ; Таблица знакогенератора: 5 байт/символ. ; W содержит код символа. Пока символов может быть ; только 50, иначе возникнет переполнение. ; Scanline содержит номер байта (не строки!) ; Сначала определим макрос, а то устанем таблицу сочинять. ; Необходимо упаковать 7 скан-строк по 5 бит в 5 байт. CharDef macro scan1, scan2, scan3, scan4, scan5, scan6, scan7 ; Следующий символ RetLW (scan? & Oxlc) >> 2 RetLW ((scan5 E, 0x10) >> 4) + ((scanb & 0xlf) << 1) + ((scan7 & 0x3) << 6) RetLW ((scan4 & 0xle) >> 1) + ((scanb & 0xf) << 4) RetLW ((scan2 & 0x18) >> 3) + ((scanb & 0xlf) << 2) + ((scan4 & 0xl) << 7) RetLW (scan1 & 0x1f) + ((scan2 & 0x7) << 5) endm FetchOneScanline IFNDEF NoDisplay ClrF PCLATH AddWF PCL, 1 NOP; else RetLW 0 endif ; А вот идет собственно таблица: Nolist ; О CharDef В'OHIO',В110001',В'10001',В'10001',В'10001',В'10001',В'01110'; 1 CharDef В'00100',В'01100',В'00100',В'00100',В100100',В'00100',В'01110'; 2 CharDef В'OHIO',В'10001',В'00001',В'00010',В100100',В'01000',В'11111'; 3 CharDef В'01110',В'10001',В'00001',В'00110',В100001',В110001',В'OHIO'; 4 CharDef В'00010',В'00110',В'01010',В'10010',В'11111',В'00010', В'00010'; 5 CharDef В'11111',В'10000',В'11110',В'00001',В'00001',В110001',В1OHIO'; б CharDef В'OHIO1.840001',В' 10000',В' НПО',В' 10001',В'10001',В'OHIO1; 7 CharDef В'11111',В'00001',В'00010',В'00100',В'01000',В'01000',В'01000'; 8 CharDef В'OHIO', В'10001',В'10001',В'OHIO', В'10001', В'10001',В'OHIO'; 9 CharDef В'OHIO', В'10001', В'10001',В'01111',В'00001',В'10001',В'OHIO' 4 Зэк Х(, Constant CharacterA = Oxa CharDef В ' 00100 ', В ' 01010 ', В ' 10001', В110001',841111', В' 10001',В' 10001' Ifndef NO_ALPHABET; В Constant CharacterW = Oxb CharDef В'11110',В'10001',B'10001',В'11110',В'10001',В'10001',В'11110' else; Р – для аона CharDef В' 11110 ',840001', В '10001', В '10001', В' 11110 ',840000', В '10000' endif; С CharDef В'01110',В'10001',В'10000',ВЧОООО',В'10000',В110001',В'01110'; о CharDef В' 11110 ',В' 10001 ',В' 10001 ',В' 10001 ',840001', В' 10001 ',841110'; Е CharDef B'lllll',ВЧ0001', В'10000', В'11110 ',В'10000', В'10001',В'11111'; F CharDef В'11111',В'10001',В'10000',В'11110',В'10ЮОО',В'10000',В'10000' ; пробел Constant SPACE_CHARACTER = 0x10 CharDef В'00000',В'ООООО',В'ООООО',В'00000',В'00000',В100000',В'00000' Constant DASH_CHARACTER = Oxll CharDef В'00000',В'00000',В'00000',В'11111',В'00000',В'ООООО',В'ООООО' List