1.2.3. П о д п р о г р а м м ы BIOS, в о з в р а щ а ю щ и е п а р а м е т р ы Всякая мудрость хороша, если ее кто-нибудь понял. Непонятая мудрость может запылиться. Д. Хармс Многие подпрограммы BIOS возвращают один или несколько параметров. Эти результаты, разумеется, можно передать через ячейки RAM с явно заданным адресом непосредственно перед выходом из подпрограммы. В дальнейшем приме- нение функции PEEK позволит Вам прочитать полученные данные. Однако, когда подпрограмма возвращает только одно значение, проще все- го присвоить его результат переменной в операторе: R = USR(A) , где: α) USR ("USeR"-"пользователь") - служебное слово; β) R - имя переменной-результата работы подпрограммы; γ) A - арифметическое выражение, значение которого совпадает со зна- чением аргумента. П р и м е р 1. Проверка состояния джойстиков и передача значений через ───────────── переменную в программу на MSX-BASIC. Подпрограмма с именем GTSTCK позволяет ввести данные с одного из трех джойстиков. Джойстик при этом выбирается по содержимому регистра А (0, 1 или 2); прочитанное значение помещается в регистр А. Если номер джойстика задается посредством аргумента функции USR(), то подпрограмма может быть "запущена" путем обращения к подпрограмме ROM, на- чинающейся с адреса &H521F. Как только значение аргумента помещено в ре- гистр А, вызывается подпрограмма с именем GTSTCK. Содержимое регистра А (состояние джойстика) затем передается в основную программу через ре- гистр HL. ┌────────────────────────────────────────────────────────────────┐ │ Подпрограмма, размещенная с адреса &H2F99, передает содержимое │ │ регистра HL программе, составленной на языке MSX-BASIC. │ └────────────────────────────────────────────────────────────────┘ Подпрограмма на языке ассемблера выглядит следующим образом: D000 CD,1F,52 CALL 521F ; В A помещается однобайтный аргумент D003 CD,D5,00 CALL 00D5 ; A=STICK(A) D006 26,00 LD H,0 ; В регистр H помещается 0 D008 6F LD L,A ; Содержимое А помещается в L D00A C3,99,2F JP 2F99 ; Содержимое регистра HL передается ; основной программе D00D C9 RET Приведем теперь программу на языке MSX-BASIC. 10 CLEAR 200,&HD000 'Резервирование области в RAM 20 AD=&HD000 30 READ A$:IF A$="Z" THEN 100 50 A=VAL("&H"+A$):POKE AD,A:AD=AD+1:GOTO 30 100 DEFUSR=&HD000 110 A=USR(0) 120 IF A<>0 THEN PRINT A 130 GOTO 110 220 DATA CD,1F,52 :' CALL 521F 230 DATA CD,D5,00 :' CALL 00D5 240 DATA 26,00 :' LD H,0 250 DATA 6F :' LD L,A 260 DATA C3,99,2F :' JP 2F99 270 DATA C9,"Z" :' RET Вы легко убедитесь, что функция USR(0) здесь "работает" точно так же, как функция STICK(0)! Перечислим теперь некоторые подпрограммы, возвращающие параметры: 1) чтение из видеопамяти LD HL,adrVRAM CALL 004A LD H,0 LD L,A CALL 2F99 RET 2) начальный адрес атрибутов спрайта CALL 521F CALL 004A CALL 2F99 RET 3) размер спрайта CALL 008A LD H,0 LD L,A CALL 2F99 RET 4) чтение числа из звукогенератора CALL 521F CALL 0096 LD H,0 LD L,A CALL 2F99 RET 5) задержка до нажатия клавиши и чтение ее кода CALL 009F LD H,0 LD L,A CALL 2F99 RET 6) чтение состояния рукоятки джойстика CALL 521F CALL 00D5 LD H,0 LD L,A CALL 2F99 RET 7) чтение состояния кнопки джойстика CALL 521F CALL 00D8 LD H,0 LD L,A CALL 2F99 RET 8) чтение состояния клавиши на графическом планшете CALL 521F CALL 00DB LD H,0 LD L,A CALL 2F99 RET 9) чтение статуса манипулятора PDL CALL 521F CALL 00DE LD H,0 LD L,A CALL 2F99 RET 1.2.4. П р и м е р ы П р и м е р 1. Чтение символа с заданной позицией из буфера клавиатуры ───────────── 10 CLEAR 200,&HA000:DEFUSR=&HA000:POKE &HA100,2 '◀── Позиция символа 20 FOR I=0 TO 14:READ R$:POKE &HA000+I,VAL("&h"+R$):NEXT 30 Z=USR(0) 40 DATA CD,B4,00 :' CALL 00B4h 50 DATA 3A,00,A1 :' LD A,(A100h) 60 DATA 4F :' LD C,A 70 DATA 06,00 :' LD B,0 80 DATA 09 :' ADD HL,BC 90 DATA 7E :' LD A,(HL) 100 DATA CD,A2,00 :' CALL 00A2h 110 DATA C9 :' RET П р и м е р 2. Вывод на экран слова "Миша"! ───────────── 10 AD=&HD000:DEFUSR=&HD000 20 READ A$:IF A$="Z" THEN A=USR(0):END 30 POKE AD,VAL("&h"+A$) 40 AD=AD+1:GOTO 20 50 DATA 3E,ED :' LD A,ED 60 DATA CD,A2,00 :' CALL 00A2h;Вывод на экран содержимого регистра А 70 DATA 3E,C9 :' LD A,C9 80 DATA CD,A2,00 :' CALL 00A2h;Вывод на экран содержимого регистра А 90 DATA 3E,DB :' LD A,DB 100 DATA CD,A2,00 :' CALL 00A2h;Вывод на экран содержимого регистра А 110 DATA 3E,C1 :' LD A,C1 120 DATA CD,A2,00 :' CALL 00A2h;Вывод на экран содержимого регистра А 130 DATA C9 :' RET 140 DATA "Z" :' К о н е ц П р и м е р 3. Вывод на экран дисплея н е п о д в и ж н о г о ────────────── спрайта. 10 SCREEN 1 20 KEY OFF:CLEAR 300,&HD000:I=&HD000 30 READ A$:IF A$="z" THEN SCREEN 1:GOTO 50 40 POKE I,VAL("&h"+A$):I=I+1:GOTO 30 50 DEFUSR=&HD00C:A=USR(0) 60 DATA FF,FF,C3,C3:'Д а н н ы е 70 DATA C3,C3,FF,FF:'Д а н н ы е 80 DATA 64,01,00,0F:'X, Y, Ш а б л о н , Ц в е т 90 DATA 21,00,D0 :'LD HL,D000 100 DATA 11,00,38 :'LD DE,3800 110 DATA 01,08,00 :'LD BC,0008 120 DATA CD,5C,00 :'CALL 005C 130 DATA 21,08,D0 :'LD HL,D008 140 DATA 11,00,1B :'LD DE,1B00 150 DATA 01,04,00 :'LD BC,0004 160 DATA CD,5C,00 :'CALL 005C 170 DATA 21,09,D0 :'LD HL,D009 180 DATA 34 :'INC (HL) 190 DATA C9 :'RET 230 DATA"z" :'К о н е ц П р и м е р 4. Вывод на экран дисплея д в и ж у щ е г о с я ────────────── спрайта 10 SCREEN 1 20 KEY OFF:CLEAR 300,&HD000:I=&HD000 30 READ A$:IF A$="z" THEN SCREEN 1:GOTO 50 40 POKE I,VAL("&h"+A$):I=I+1:GOTO 30 50 DEFUSR=&HD00C:A=USR(0) 60 DATA FF,FF,C3,C3:'Д а н н ы е 70 DATA C3,C3,FF,FF:'Д а н н ы е 80 DATA 64,01,00,0F:'X, Y, Ш а б л о н , Ц в е т 90 DATA 21,00,D0 :'LD HL,D000 100 DATA 11,00,38 :'LD DE,3800 110 DATA 01,08,00 :'LD BC,0008 120 DATA CD,5C,00 :'CALL 005C 130 DATA 21,08,D0 :'LD HL,D008◀┐ 140 DATA 11,00,1B :'LD DE,1B00 │ 150 DATA 01,04,00 :'LD BC,0004 │ 160 DATA CD,5C,00 :'CALL 005C │ 170 DATA 21,09,D0 :'LD HL,D009 │ 180 DATA 34 :'INC (HL) │ 190 DATA CD,BA,00 :'CALL 00BA │ 200 DATA 06,F1,00 :'LD B,F1◀─┐ │Задержка 210 DATA 10,FD :'DJNZ ─┘ │Задержка 220 DATA C3,17,D0 :'JP D017 ───┘ 230 DATA"z" :'К о н е ц П р и м е р 5. Столкновение спрайтов ────────────── 10 POKE &HD000,0:KEYOFF 20 SCREEN 1:SPRITE$(0)="orpolrplor":SPRITE$(1)="orplorlorlo" 30 DEFUSR=&H9000:D=&H9000 50 READ A$ 60 IF A$="z" THEN 180 70 POKE D,VAL("&h"+A$) 80 D=D+1 90 GOTO 50 100 DATA CD,3E,01 :' CALL 013E 110 DATA E6,20 :' AND 20 120 DATA FE,00 :' CP 0 130 DATA C8 :' RET Z 140 DATA 3E,01 :' LD A,1 150 DATA 32,00,D0 :' LD (D000),A 160 DATA C9 :' RET 170 DATA "z" :' К о н е ц 180 FOR I=0 TO 255:PUT SPRITE 1,(I,40),6,0:PUT SPRITE 2,(255-I,40),5,1 190 A=USR(0):P=PEEK(&HD000): IF P=1 THEN FOR K=0 TO 10:COLOR 1,15,15:COLOR 15,1,1:NEXT: POKE &HD000,0 200 NEXT:GOTO 180 П р и м е р 6. Мгновенное "утолщение" символов! ────────────── 10 CLEAR 100,&HA000:AD=&HA000:DEFUSR=&HA000 30 READ A$:IF A$="z"THEN 80 50 POKE AD,VAL("&h"+A$):AD=AD+1:GOTO 30 80 A=USR(0):END 90 DATA CD,6F,00 :' CALL 006Fh 100 DATA 21,08,01 :' LD HL,0108h 110 DATA 11,F8,07 :' LD DE,07F8h 120 DATA CD,4A,00 :' CALL 004Ah ◀──┐ 130 DATA 47 :' LD B,A │ 140 DATA CB,38 :' SRL B │ 150 DATA B0 :' OR B │ 160 DATA CD,4D,00 :' CALL 004Dh │ 170 DATA 7D :' LD A,L │ 180 DATA BB :' CP E │ 190 DATA CA,1C,A0 :' JP Z,A01Ch──│──┐ 200 DATA 23 :' INC HL │ │ 210 DATA C3,09,A0 :' JP A009 ───┘ │ 220 DATA 7A :' LD A,D ◀──────┘ 230 DATA BC :' CP H 240 DATA CA,25,A0 :' JP Z,A025h──┐ 250 DATA 23 :' INC HL │ 260 DATA C3,09,A0 :' JP A009h │ 270 DATA C9 :' RET ◀──┘ 280 DATA "z" :' К о н е ц П р и м е р 7. Образование слова-"перевертыша" ────────────── 10 CLEAR 400,&HD000:DEFUSR=&HD00F:A=&HD00F 20 READ A$:IF A$="z" THEN R=USR(R):END ELSE 30 30 POKE A,VAL("&h"+A$):A=A+1:GOTO 20 40 DATA CD,C3,00 :' CALL 00C3 ; Очистка экрана 50 DATA CD,B4,00 :' CALL 00B4 ; Ввод строки 60 DATA 06,11 :' LD B,11h ; Загрузка параметра цикла 70 DATA 23 :' INC HL ; ◀──────┐ 80 DATA 10,FD :' DJNZ $-1 ; ───────┘ 90 DATA 06,11 :' LD B,11h ; Загрузка параметра цикла 100 DATA 7E :' LD A,(HL) ; 110 DATA 2B :' DEC HL ; 120 DATA CD,A2,00 :' CALL 00A2 ; Печать символа, код которого содер- ; жится в регистре A 130 DATA 10,F9 :' DJNZ $-5 ; Цикл, организованный для печати ; слова 140 DATA C9 :' RET ; К о н е ц 150 DATA "z" П р и м е р 8. Вычеркивание из слова латинской буквы "А" ────────────── 10 CLEAR 200,&HD000:DEFUSR=&HD001:A=&HD001 20 READ R$:IF R$="z" THEN 40 30 POKE A,VAL("&h"+R$):A=A+1:GOTO 20 40 P=USR(0) 45 DATA CD,C3,00 :'CALL 00C3 ; Очистка экрана 50 DATA CD,B4,00 :'CALL 00B4 ; Ввод строки 70 DATA 3E,41 :'LD A,41 ; Загрузка кода вычеркиваемого символа 75 DATA 23 :'INC HL ; 80 DATA BE :'CP (HL) ; 90 DATA 28,04 :'JR Z,$+6 ; 100 DATA 7E :'LD A,(HL) ; 110 DATA CD,A2,00 :'CALL 00A2 ; Вывод символа с кодом,содержащимся в ; регистре А 120 DATA 3E,00 :'LD A,00 ; 130 DATA BE :'CP (HL) ; 140 DATA 28,02 :'JR Z,$+3 ; Выход из программы по биту Z 141 DATA 18,EF :'JR $-15 ; 145 DATA C9 :'RET ; 150 DATA "z" П р и м е р 9. Подсчет количества символов во введенном слове ───────────── 10 CLEAR 200,&HD000:DEFUSR=&HD001:A=&HD001 20 READ R$:IF R$="z" THEN 40 30 POKE A,VAL("&h"+R$):A=A+1:GOTO 20 40 P=USR(0) 45 DATA CD,C3,00 :' CALL 00C3 ; Очистка экрана 50 DATA CD,B4,00 :' CALL 00B4 ; Ввод слова 60 DATA 06,00 :' LD B,00 ; 70 DATA 3E,00 :' LD A,00 ; 75 DATA 23 :' INC HL ; 80 DATA BE :' CP (HL) ; 90 DATA 28,03 :' JR Z,$+5 ; 100 DATA 04 :' INC B ; 110 DATA 18,F7 :' JR $-7 ; 120 DATA 78 :' LD A,B ; 130 DATA 32,00,A0 :' LD (A000),A; 140 DATA C9 :' RET ; 150 DATA "z" 160 PRINT PEEK(&HA000) П р и м е р 10. Иллюстрация работы подпрограммы BIOS по адресу 0010h ─────────────── 10 CLEAR 100,&HD000:DEFUSR=&HD000:AD=&HD000 40 C$="YAMAHA !!!":C=LEN(C$) 50 FOR I=1 TO LEN(C$) 60 POKE &HA000+I,ASC(MID$(C$,I,1)) 70 NEXT 80 READ A$:IF A$="z"THEN 120 100 POKE AD,VAL("&h"+A$):AD=AD+1:GOTO 80 120 POKE &HD001,C:A=USR(0):END 130 DATA 06,00 :' LD B,0 ;В регистре B уже находится длина ;слова C$ 140 DATA 21,00,A0 :' LD HL,A000 150 DATA CD,10,00 :' CALL 0010 ;◀──┐ 160 DATA CD,A2,00 :' CALL 00A2 ; │ 170 DATA 10,F8 :' DJNZ D005 ;───┘ 180 DATA C9 :' RET 190 DATA "z" П р и м е р 11. Использование текстового представления для установки ────────────── т о ч к и на графическом экране. 10 SCREEN 7 20 POKE &HA000,&H28 :'Загрузка кода ASCII символа "(" 30 POKE &HA001,&HF :'Управляющий код. Если координата X двухбайтовая, то управляющий код равен &H1C, иначе - &h0F 40 POKE &HA002,&HFF :'Координата X 50 POKE &HA003,&H2C :'Код ASCII символа "," 60 POKE &HA004,&HF :'Управляющий код 70 POKE &HA005,&H1A :'Координата Y 80 POKE &HA006,&H29 :'Код ASCII символа ")" 90 POKE &HA007,&H2C :'Код ASCII символа "," 100 POKE &HA008,&HF :'Управляющий код 110 POKE &HA009,&HF :'Код цвета т о ч к и 120 POKE &HA00A,&H0 :'Конец т е к с т о в о г о представления 130 CLEAR 200,&HD000:DEFUSR=&HD000:P=&HD000 140 READ A$ 150 IF A$="z" THEN GOTO 170 160 POKE P,VAL("&h"+A$):P=P+1:GOTO 140 170 A=USR(0) 180 DATA 21,00,A0 :'LD HL,A000 Загрузка адреса текстового представления оператора 190 DATA F7,87,6D,00 :'RST 30[87/006D] Обращение к подпрограмме BIOS 200 DATA c9,"z" 210 A$=INPUT$(1) П р и м е р 12. Вывод на экран дисплея числа из регистра B ─────────────── 10 DATA 3A,00,E0 :' D000:LD A,(E000) ;Исходное число 20 DATA 47 :' LD B,A ;сохраняем в регистре B 30 DATA CD,12,D0 :' CALL D012 ;──────────────────────┐ 40 DATA CD,A2,00 :' CALL 00A2 ;Печатаем символ │ 50 DATA 78 :' LD A,B ;Восстанавливаем │ 60 DATA CD,16,D0 :' CALL D016 ;──────────────────────│┐ 70 DATA CD,A2,00 :' CALL 00A2 ;Печатаем символ ││ 80 DATA C9 :' RET ;Возврат в MSX-BASIC ││ 90 DATA 0F :'D012: RRCA ;◀─────────────────────┘│ 100 DATA 0F :' RRCA ;Ставим старший полубайт│ 110 DATA 0F :' RRCA ;на место младшего │ 120 DATA 0F :' RRCA ; ▼ 130 DATA E6,0F :'D016: AND 0F ;Выделяем младший полубайт 140 DATA 0E,0A :' LD C,0A ;Сравниваем с 10 150 DATA B9 :' CP C ;··· 160 DATA FA,21,D0 :' JP M,D021 ;Если меньше, то ───────┐ 170 DATA C6,37 :' ADD A,37 ; │ 180 DATA C9 :' RET ; │ 190 DATA C6,30 :'D021: ADD A,30 ;◀──────────────────────┘ 200 DATA C9 :' RET ; 210 ' :'E000: заданное число 220 FOR I=0 TO 35: READ A$ 230 POKE &HD000+I,VAL("&h"+A$) 240 NEXT I 245 PRINT"Введите целое число, не превышающее 255"; 250 INPUT BYTE: POKE &HE000,BYTE 255 PRINT"Ваше число в шестнадцатеричном виде: &h"; 260 DEFUSR=&HD000:Z=USR(0) run Введите целое число, не превышающее 255? 255 Ваше число в шестнадцатеричном виде: &hFF Ok П р и м е р 13. Ввод в память компьютера числа с клавиатуры при помо- ─────────────── щи подпрограммы BIOS 5' Автор программы: Поляков С.,10-й класс. 14.01.89 10 CLEAR 200,&HD000:AD=&HD000 30 READ A$:IF A$="z" THEN 60 50 A=VAL("&h"+A$):POKE AD,A:AD=AD+1:GOTO 30 60 DEFUSR=&HD000 70 PRINT"Введите десятичное трехзначное число от 0 до 255:" 80 A=USR(0):PRINT"Вы ввели число:"PEEK(&HB000):END 110 DATA F7,00,B4,00 :'RST 30[00/00B4];BIOS ввода строки 120 DATA 23 :'INC HL 130 DATA 7E :'LD A,(HL) ;В А - код первого символа 140 DATA 06,63 :'LD B,63h ;Блок получения числа сотен 150 DATA D6,30 :'SUB 30h ;;; В регистре А - число 160 DATA 57 :'LD D,A ;;; 170 DATA 8A :'ADC A,D ;;; 180 DATA 10,FD :'DJNZ $-1 ;;; 190 DATA 5F :'LD E,A ;В регистрах А и Е - число 200 DATA 16,00 :'LD D,00h ;сотен, умноженное на 100 210 DATA D5 :'PUSH DE ;Результат - в регистре DE 220 DATA 23 :'INC HL 230 DATA 7E :'LD A,(HL) ;В А - код второго символа 240 DATA 06,09 :'LD B,09h ;Блок получения числа десятков 250 DATA D6,30 :'SUB 30h ;;; В регистре А - число 260 DATA 57 :'LD D,A ;;; 270 DATA 8A :'ADC A,D ;;; 280 DATA 10,FD :'DJNZ $-1 ;;; 290 DATA D1 :'POP DE ; 300 DATA 8B :'ADC A,E ; 310 DATA 5F :'LD E,A ;В регистрах А и Е - сумма со- 320 DATA D5 :'PUSH DE ;тен и десятков 330 DATA 23 :'INC HL ; 340 DATA 7E :'LD A,(HL) ;В А - код третьего символа 350 DATA D6,30 :'SUB 30h ;В регистре А - число 360 DATA D1 :'POP DE 370 DATA 8B :'ADC A,E ;В А - введенное нами число 380 DATA 6F :'LD L,A 390 DATA 26,00 :'LD H,00 400 DATA 22,00,B0 :'LD (B000h),HL 410 DATA C9 :'RET 420 DATA "z" Письмо это вышло более длинным только потому, что мне некогда было написать его покороче. Б.Паскаль. Письма к провинциалу, 16-е письмо П р и м е р 14. Инициализация текстово-графического режима SCREEN 1-2 ────────────── на компьютерах MSX-1. 10 CLEAR 400,&HD000:DEFUSR=&HD000:K=&HD000 40 READ A$:IF A$="Z" THEN A=USR(0):END 60 POKE K,VAL("&H"+A$):K=K+1:GOTO 40 90 DATA CD,6F,00 :' CALL 006F ;Режим SCREEN 1 100 DATA 3E,20 :' LD A,20 ; 110 DATA 32,B0,F3 :' LD (F3B0),A ;Установка 32 симв.в строке 120 DATA CD,7E,00 :' CALL 007E ;Установка SCREEN 1-2 130 DATA 21,00,00 :' LD HL,0000 ; 140 DATA 11,BF,1B :' LD DE,1BBF ; 150 DATA 1A :' LD A,(DE) ◀─────┐; ┌───────────────────┐ 160 DATA CD,2A,D0 :' CALL D02A ─────┐ │; │ Часть программы, │ 170 DATA 3E,F0 :' LD A,F0 │ │; │ │ 180 DATA CB,EC :' SET 5,H │ │; │ │ 190 DATA CD,2A,D0 :' CALL D02A ───┐ │ │; │ │ 200 DATA CB,AC :' RES 5,H │ │ │; │ │ 210 DATA 13 :' INC DE │ │ │; │ которая │ 220 DATA 23 :' INC HL │ │ │; │ │ 230 DATA 7C :' LD A,H │ │ │; │ │ 240 DATA D6,08 :' SUB 08 │ │ │; │ │ 250 DATA C2,11,D0 :' JP NZ,D011 ─┼─┼─┘; │ │ 260 DATA 00 :' NOP │ │ ; │ считывает │ 270 DATA C3,3F,D0 :' JP D03F ──┼─┼┐ ; │ │ 280 DATA 47 :' LD B,A ◀──┘◀┘│ ; │ │ 290 DATA CD,4D,00 :' CALL 004D │ ; │ │ 300 DATA CB,DC :' SET 3,H │ ; │ │ 310 DATA 78 :' LD A,B │ ; │ шаблоны │ 320 DATA CD,4D,00 :' CALL 004D │ ; │ │ 330 DATA CB,9C :' RES 3,H │ ; │ │ 340 DATA CB,E4 :' SET 4,H │ ; │ │ 350 DATA 78 :' LD A,B │ ; │ символов │ 360 DATA CD,4D,00 :' CALL 004D │ ; │ │ 370 DATA CB,A4 :' RES 4,H │ ; └───────────────────┘ 380 DATA C9 :' RET │ ; 390 DATA 21,F8,0F :' LD HL,0FF8 ◀──┘ ; 400 DATA 3E,FF :' LD A,FF ; 410 DATA CD,51,D0 :' CALL D051 ────┐ ; 420 DATA CD,4E,D0 :' CALL D04E ───┐│ ; 430 DATA C9 :' RET ││ ; К о н е ц 440 DATA 00,00,00 :' ││ ; 450 DATA 21,F8,17 :' LD HL,17F8◀┘│ ; 460 DATA 06,08 :' LD B,8 ◀────┘ ;Подпрограмма,"считывающая" 470 DATA CD,4D,00 :' CALL 004D◀──┐ ;курсор для 2-й и 3-й час- 480 DATA 23 :' INC HL │ ;тей экрана 490 DATA 10,FA :' DJNZ $ - 4──┘ ; 500 DATA C9 :' RET 510 DATA "Z" 1.3. Р а б о т а с п о д п р о г р а м м а м и BDOS Кроме подпрограмм BIOS в версии MSX-Disk BASIC, а также в операционной системе MSX-DOS поддерживаются подпрограммы системы BDOS. Подпрограммы BDOS вызываются следующим образом: α) из операционной системы MSX-DOS: ┌─────────────────────────────┐ │ LD C,номер подпрограммы │ │ CALL 0005h │ └─────────────────────────────┘ β) из системы MSX-Disk BASIC: ┌─────────────────────────────┐ │ LD C,номер подпрограммы │ │ CALL F37Dh │ └─────────────────────────────┘ Приведем несколько примеров вызова подпрограмм BDOS из системы MSX-Disk BASIC. П р и м е р 1. Вывод с и м в о л а на экран. ───────────── 10 CLEAR 200,&HC000:DEFUSR=&HC000 20 DATA &H1E,64 :'В регистре E - код символа 30 DATA &H0E,&H02 :'LD C,02h ;Номер подпрограммы 40 DATA &HCD,&H7D,&HF3 :' ;Обращение к BDOS 50 DATA &HC9 :'RET 60 FOR T=0 TO 7:READ J:POKE &HC000+T,J:NEXT 70 A=USR(A) :' На экране появляется символ! П р и м е р 2. Попробуем у н и ч т о ж и т ь имя файла с диска. ───────────── 10 CLEAR 200,&HC000:DEFUSR=&HC000 20 PRINT"Имя файла состоит из 8 символов, точки и еще 3 символов!" 30 INPUT"Какое имя уничтожить:";F$ 70 'Запись имени файла в FCB 80 POKE &HE000,1 'Дисковод A: 90 FOR T=1 TO 8:POKE &HE000+T,ASC(MID$(F$,T,1)):NEXT 'Имя файла 100 FOR T=9 TO 11:POKE &HE000+T,ASC(MID$(F$,T+1,1)):NEXT 'Расширение 110 'Подпрограмма DELETE FILE 120 DATA &H11,&H00,&hE0 :'LD DE,E000h;адрес FCB 130 DATA &H0E,&H13 :'LD C,13h ;Номер подпрограммы 140 DATA &HCD,&H7D,&HF3 :'CALL F37Dh 150 DATA &HC9 :'RET 160 FOR T=0 TO 8:READ J:POKE &HC000+T,J:NEXT 170 A=USR(A): PRINT"Operation complete" П р и м е р 3. Вывод ч е т ы р е х б а й т н о г о числа, содержа- ────────────── щегося в регистрах HL и DE на экран дисплея (авторы алгоритма: J.Suzuki и T.Patterson). Программа "вырезана" А.Никитиным из файла COMMAND.COM , поэтому,к сожа- лению, она написана на Макроассемблере. BDOS EQU #0005 ; Aдрес, нужный для доступа к BDOS ; LD HL,12 ; В регистре HL содержатся младшие два байта вы- LD DE,0 ; водимого числа, а в регистре DE - старшие два ; байта LD BC,0 ; Очистка ячеек памяти, нужных для перевода чис- LD (METKA),BC ; ла из шестнадцатеричного вида в десятичный LD (METKA+2),BC ; LD C,#20 ; В регистре С - число 20h (п о ч е м у!?) LOOP1: ADD HL,HL ; Сложение и сдвиги необходимы для установки RL E ; флага C регистра флагов, а следовательно, и RL D ; для увеличения содержимого регистра E,a затем PUSH HL ; и регистра D . LD HL,METKA ; Считывание предыдущих результатов вычислений LD B,#04 ; и (при выполнении условия переполнения регист- ZAPOL: LD A,(HL) ; ра D) увеличениe их содержимого ADC A,A ; Обратите внимание на эту команду: она увеличи- DAA ; вает содержимое регистра А при установленном LD (HL),A ; флаге C INC HL ; DJNZ ZAPOL ; POP HL ; DEC C ; Уменьшение значения цикла. JR NZ,LOOP1 ; На выходе из этого цикла в ячейках METKA ÷ ; METKA+3 будет лежать Ваше число в десятичном ; виде LD BC,#0410 ; ПервыЙ байт - данные для работы цикла, второй ; байт нужен для коррекции кода числа LD HL,METKA+3 ; Число выводится со старшего байта PRINT: LD A,(HL) ; Блок печати числа RRA ; RRA ; RRA ; RRA ; "Переворачивание" числа... CALL POLBYTE ; ...и переход на печать младшего полубайта LD A,#01 ; Проверка, последняя ли это цифра SUB B ; JR NZ,STEK ; Если выводимая цифра является последней и она- LD C,A ; - нуль, то вывод символа "нуль" STEK: LD A,(HL) ; DEC HL ; CALL POLBYTE ; Переход на печать старшего полубайта DJNZ PRINT ; RET ; К о н е ц программы POLBYTE:AND #0F ; "Отрезание" младшего полубайта JR Z,SUMMA ; Если это число - нуль, то - печать символа ; "пробел" LD C,#00 ; Иначе - печать самого числа ──────┐ SUMMA: OR #30 ; Получение кода данного числа │ SUB C ; Корректирование кода ◀──────┘ WYWOD: PUSH AF ; Сохранение содержимого всех регистров PUSH BC ; PUSH DE ; PUSH HL ; LD E,A ; Печать числа по коду (из регистра E) LD C,#02 ; CALL BDOS ; POP HL ; POP DE ; POP BC ; POP AF ; RET ; METKA: DEFS 4 ; Область памяти,необходимая для арифметических ; расчетов 1.4 И с п о л ь з о в а н и е л о в у ш е к ... И тут Пух все понял. Они с Пятачком попались в Хитрую Ловушку для Пухов, которую в отмест- ку им вырыл Слонопотам!... Отрывок из неопубликованной главы повести А.Милн "Винни-Пух и все-все-все" Вы,конечно,помните, что программы, выполняющие всю "черную" работу,"за- шиты" в ROM, поэтому изменить их н е в о з м о ж н о. Однако,в некоторых важных подпрограммах ROM предусмотрены своеобразные "перехваты" - л о в у- ш к и ("hooks"). Вызов подпрограммы-ловушки организуется в ROM следующим образом: PUSH HL ; Сохранение содержимого PUSH DE ; регистров микропроцессора PUSH BC ; в стеке PUSH AF ; CALL а д р е с ; Вызов подпрограммы-ловушки по заданному адресу POP AF ; Восстановление значения POP BC ; регистров микропроцессора POP DE ; для дальнейших операций POP HL ; При включении компьютера подпрограмма-ловушка содержит только команду возврата (RET). Вы м о ж е т е заменить эту команду на команду перехода (JP) к подпрограмме, которая написана Вами на машинном языке. ┌───────────────────────────────────────────────────────────────────────┐ │ В этом случае о ловушке говорят, что она о б р а б а т ы в а е т с я.│ └───────────────────────────────────────────────────────────────────────┘ Таким образом, Вы можете косвенно изменять ROM и вводить н о в ы е операторы! Приведенный ниже рисунок показывает, что означает термин "обра- ботать" ловушку. ┌───────────────────────────────┬───────────────────────────────────────┐ │ ┌───────────────────────────┐ │ │ │ │Предыдущая подпрограмма ROM│ │ │ │ └──────────┬────────────────┘ │ ┌──────────────────┐ │ │ └──────────────────│──▶ Необрабатываемая │ │ │ ┌──────────────────│──┤ ловушка │ │ │ ┌──────────▼────────────────┐ │ └──────────────────┘ │ │ │ Следующая подпрограмма ROM│ │ │ │ └───────────────────────────┘ │ │ │ ┌───────────────────────────┐ │ │ │ │Предыдущая подпрограмма ROM│ │ ┌──────────────┐ │ │ └──────────┬────────────────┘ │ ┌────────────────┐ │ Ваша │ │ │ └──────────────────│──▶ Обрабатываемая │──▶ подпрограмма │ │ │ │ │ ловушка │ │ обработки │ │ │ │ └────────────────┘ └───────┬──────┘ │ │ ┌──────────────────│──────────────────────────────┘ │ │ ┌──────────▼────────────────┐ │ │ │ │ Следующая подпрограмма ROM│ │ │ │ └───────────────────────────┘ │ │ └───────────────────────────────┴───────────────────────────────────────┘ П р и м е р 1. О т м е н а действия клавиши "STOP". ───────────── При в ы п о л н е н и и п р о г р а м м ы на языке MSX-BASIC клавиатура постоянно опрашивается (сканируется). Нажатие клави- ши порождает код, который записывается в буфер клавиатуры (начинающийся с адреса &HF55E в рабочей области). До этого код нажатой клавиши временно записывается в слово NEWKEY, начинающееся с адреса &HFBE5. Регистр А микропроцессора необходимо загрузить значением ┌──────────────┐ │ 8·NS+NC │, └──────────────┘ где: NS - номер строки матрицы клавиатуры; NC - номер столбца матрицы клавиатуры. Поэтому поместим в регистр A значение 8·7+4=60=&H3C . ▲ ▲ Номер с т р о к и матрицы ─┘ └─ Номер с т о л б ц а матрицы клавиатуры,содержащей клавишу клавиатуры,содержащей клавишу "STOP" "STOP" Затем осуществим переход на ловушку с именем KEYKOD , расположенную по адресу &HFDCC . Обычно ловушка занимает 5 байтов памяти, содержащих только команду ас- семблера RET (ее код &HC9). Введем вместо нее переход на подпрограмму о б- р а б о т к и л о в у ш к и . Эта подпрограмма будет действовать только при нажатии клавиши "STOP". 10 CLEAR 200,&HD000 'Зарезервируем область для хранения подпрограммы ' обработки ловушки 20 POKE &HFDCC,&HC3 'Запишем команду перехода на ловушку с именем 30 POKE &HFDCD,&H00 ' KEYCOD : ┌───────────┐ 40 POKE &HFDCE,&HD0 ' C3,00,D0 │ JP D000 │ 50 AD=&HD000 └───────────┘ 60 READ A$:IF A$="Z" THEN END 70 POKE AD,VAL("&H"+A$) 80 AD=AD+1:GOTO 60 100 'П о д п р о г р а м м а о б р а б о т к и л о в у ш к и 120 DATA FE,3C :' CP 3C ;Сравниваем константу 3Ch с ;содержимым регистра A 130 DATA C0 :' RET NZ ; "нет" ──▶ выход 140 DATA 3E,FD :' LD A,FD ; A=FD 150 DATA 32,EB,FB :' LD (FBEBh),A ; A ──▶ FBEB 160 DATA 3E,3C :' LD A,3C ; A=3C 170 DATA C9 :' RET ; Выход 180 DATA "Z" :' Выполните эту программу: обратите внимание на тот факт,что нажатие кла- виши STOP производит такой же эффект, как и нажатие клавиш "CTRL"+"STOP" в к о м а н д н о м режиме. Подпрограмма обработки ловушки посылает значение &H11111101=&HFD по адресу &HFBEB (шестая строка матрицы клавиатуры),имитируя тем самым на- жатие клавиши "CTRL". При этом нажатие клавиши "STOP" будет прочитано как одновременное нажатие клавиш "CTRL" и "STOP",что будет обработано в MSX- -BASIC уже по обычным правилам. Удалите вышеприведенную программу и введите новую программу: 10 POKE &HFBB0,1 20 ON STOP GOSUB 100:STOP ON 30 PRINT A:A=A+1:GOTO 30 100 RETURN Нажатие клавиши "STOP" теперь не приводит к прекращению программы и вы- воду на экран курсора. Поскольку клавиша "STOP" превращена в"CTRL"+"STOP", то клавиша "STOP" "перестает работать". Отметим, что нажатие сложной комбинации клавиш "CTRL"+"SHIFT"+"GRAPH"+"РУС" прекращает работу этой программы. П р и м е р 2. При нажатии функциональной клавиши F4 печатается слово ───────────── "Миша". 10 CLEAR 200,&HD000 20 POKE &HFDCC,&HC3 ':\ 30 POKE &HFDCD,&H0 ': > JP D000 40 POKE &HFDCE,&HD0 ':/ 50 AD=&HD000 60 READ A$:IF A$="Z" THEN END 70 POKE AD,VAL("&H"+A$) 80 AD=AD+1: GOTO 60 90 DATA FE,38 :' CP 38h ; A:=38h ? 100 DATA C0 :' RET NZ ; Символ ":=" означает "содержит" 110 DATA 3E,ED :' LD A,EDh ; A:=EDh ───▶"М" 120 DATA CD,A2,00 :' CALL 00A2 ; 130 DATA 3E,C9 :' LD A,C9h ; A:=C9h ───▶"и" 140 DATA CD,A2,00 :' CALL 00A2 ; 150 DATA 3E,DB :' LD A,DBh ; A:=DBh ───▶"ш" 160 DATA CD,A2,00 :' CALL 00A2 ; 170 DATA 3E,C1 :' LD A,C1h ; A:=C1h ───▶"а" 180 DATA CD,A2,00 :' CALL 00A2 ; 190 DATA 3E,40 :' LD A,40h ; A:=40h 200 DATA C9 :' RET ; 210 DATA "Z" :' К о н е ц ; П р и м е р 3. Команда RUN приводит к появлению на экране слова ───────────── "Миша". 10 CLEAR 200,&HD000 20 POKE &HFECB,&HC3 ':\ 30 POKE &HFECC,&H0 ': > JP D000 40 POKE &HFECD,&HD0 ':/ 50 AD=&HD000 60 READ A$:IF A$="Z" THEN END 70 POKE AD,VAL("&H"+A$) 80 AD=AD+1:GOTO 60 90 DATA 3E,ED :' LD A,EDh ; A:=EDh ───▶"М" 100 DATA CD,A2,00 :' CALL 00A2 ; 110 DATA 3E,C9 :' LD A,C9h ; A:=C9h ───▶"и" 120 DATA CD,A2,00 :' CALL 00A2 ; 130 DATA 3E,DB :' LD A,DBh ; A:=DBh ───▶"ш" 140 DATA CD,A2,00 :' CALL 00A2 ; 150 DATA 3E,C1 :' LD A,C1h ; A:=C1h ───▶"а" 160 DATA CD,A2,00 :' CALL 00A2 ; 170 DATA C9 :' RET ; 180 DATA "Z" :' К о н е ц ; П р и м е р 4. ───────────── Программа позволяет на слух оценивать частоту обращений к ловушкам по маскируемым прерываниям. Во время очередного прерывания по таймеру издает- ся звонок-сигнал. Таким образом ловушка "прозванивается". .Z80 LD HL,OBJ ; Организация псевдо-ROM LD DE,04000H ; в 1-й странице слота 3-2 LD BC,80H ; LDIR ; LD HL,START ; Создание структуры страниц LD DE,09000H ; должно происходить в "верхних" LD BC,OBJ-START ; адресах LDIR ; JP 9000H ; START: DI ; LD A,0FCH ; 1-я страница - BASIC BIOS OUT (0A8H),A ; 2-я страница из слота 3-2 LD A,0A8H ; 3-я страница из слота 3-2 LD (0FFFFH),A ; 4-я страница из слота 3-2 EI ; LD HL,(4002H) ; JP (HL) ; Переход на начало основной программы OBJ: ; .PHASE 4000H ; DB 'AB' ; Идентификатор ПЗУ DW NACH ; Адрес начала программы DW 0 ; Зарезервированы 12 байтов DW 0 ; DW 0 ; DW 0 ; DW 0 ; DW 0 ; NACH: XOR A ; CALL 00C3H ; Очистка экрана CALL 00CCH ; Выключение функциальных клавиш DI ; IM 1 ; Установка 1-го режима прерываний: LD A,0C3H ; - сохраняется программный счетчик в стеке; LD (0FD9AH),A ; - переход по адресу 038H, где происходит LD HL,WORK ; обращение к адресам 0FD9AH и 0FD9FH LD (0FD9BH),HL ; с частотой 60 Гц.Любой из адресов можно EI ; использовать для обработки прерываний LABEL: JR LABEL ; WORK: ; LD A,7 ; Это и есть подпрограмма, генерирующая OUT (0A0H),A ; звонок-сигнал! LD A,10111110B ; OUT (0A1H),A ; LD A,8 ; OUT (0A0H),A ; LD A,10H ; OUT (0A1H),A ; LD A,11 ; OUT (0A0H),A ; LD A,100 ; OUT (0A1H),A ; LD A,12 ; OUT (0A0H),A ; LD A,0 ; OUT (0A1H),A ; LD A,13 ; OUT (0A0H),A ; LD A,1 ; OUT (0A1H),A ; RET ; .DEPHASE ; END ; П р и м е р 5. Перемещение спрайта по прерываниям ────────────── ;Некоторые макроопределения: DISK MACRO ; LD BC,0100H ; DSK:PUSH BC ; CALL 0FD9FH ; POP BC ; LD A,B ; Гашение лампочки дисковода OR C ; для YIS805/128 КУВТ 2 RET Z ; DEC BC ; JR DSK ; ENDM ; ; GASI MACRO ; BCALL 041H ; В ы к л ю ч е н и е экрана ENDM ; ; GORI MACRO ; BCALL 044H ; В к л ю ч е н и е экрана ENDM ; ; NETEND MACRO ; RST 030H ; DEFB 08FH ; Отключение от с е т и (только для MSX-2) DEFW 04016H ; ENDM ; BCALL MACRO @X ; RST 030H ; DEFB 0 ; Межслотовые вызовы подпрограмм DEFW @X ; ENDM ; CLS MACRO ; XOR A ; Очистка экрана BCALL 0C3H ; ENDM ; SCREEN2 MACRO ; LD HL,01800H ; LD (0F3C7H),HL ; LD HL,02000H ; LD (0F3C9H),HL ; LD HL,0 ; Инициализация и установка LD (0F3CBH),HL ; 2-го графического режима LD HL,01B00H ; LD (0F3CDH),HL ; LD HL,03800H ; LD (0F3CFH),HL ; BCALL 072H ; ENDM ; COLOR MACRO ; LD A,01H ; LD HL,0F3E9H ; LD (HL),A ; INC HL ; Установка цвета LD (HL),A ; INC HL ; LD (HL),A ; BCALL 062H ; ENDM ; INITSPR MACRO ; BCALL 069H ; LD BC,06201H ; Инициализация и "разрешение" BCALL 047H ; спрайтов размером 16 ╳ 16 ENDM ; VIDEO MACRO ; SNOW:DI ; LD A,E ; OUT (99H),A ; Заполнение области видеопамяти, начинающейся LD A,D ; с DE длиною в BC из области, начинающейся с HL OR 40H ; OUT (99H),A ; LD A,(HL) ; OUT (98H),A ; LD A,B ; OR C ; EI ; RET Z ; DEC BC ; INC HL ; INC DE ; JR SNOW ; ENDM ; START: ; CALL DISKETA ; Выполнение описанных макроопределений NETEND ; GASI ; COLOR ; SCREEN2 ; INITSPR ; CLS ; LD HL,SGT ; Заполнение видеопамяти шаблонами спрайта LD DE,03800H ; LD BC,20H ; CALL VRAM ; LD HL,SAT ; LD DE,01B00H ; Установка атрибутов спрайта LD BC,04H ; CALL VRAM ; GORI ; LD HL,HOOK ; LD DE,0FD9FH ; Установка адреса обработки прерываний. LD BC,5 ; Обслуживает подпрограмму обработки HOOK с DI ; адресом 0FD9Fh LDIR ; EI ; CIKL:NOP ; LD HL,SAT ; Постоянное отображение спрайта на экран, но коор- LD DE,01B00H ; динаты его меняются в подпрограмме обработки пре- LD BC,4 ; рываний в зависимости от состояния матрицы клави- CALL VRAM ; атуры. ... ; Здесь может находиться Ваша программа. ... ; Например, программа движения фона или движения ... ; других спрайтов. ... ; JR CIKL ; HOOK: RST 30H ; DEFB 8BH ; Межслотовый вызов подпрограммы DEFW STICK ; обработки прерываний RET ; STICK:LD A,8 ; Подпрограмма обработки прерываний DI ; CALL BUFF ; После обращения к BUFF LD HL,SAT ; в регистре А - состояние ряда матрицы PUSH AF ; CP 0EFH ; JR Z,LEFT ; В зависимости от нажатой клавиши ("стрелки") POP AF ; меняется координата PUSH AF ; CP 0DFH ; JR Z,SHIFT ; POP AF ; PUSH AF ; CP 0BFH ; JR Z,MAIN ; POP AF ; PUSH AF ; CP 07FH ; JR Z,RIGHT ; END: POP AF ; RET ; SHIFT:DEC (HL) ; Клавиша "Стрелка вверх" JR END ; MAIN: INC (HL) ; Клавиша "Стрелка вниз" JR END ; LEFT: INC HL ; Клавиша "Стрелка влево" DEC (HL) ; JR END ; RIGHT:INC HL ; Клавиша "Стрелка вправо" INC (HL) ; JR END ; BUFF: LD C,A ; Подпрограмма возвращает состояние "сброшенных" DI ; битов для определенного ряда матрицы клавиатуры IN A,(0AAH) ; AND 0F0H ; ADD A,C ; OUT (0AAH),A ; EI ; IN A,(0A9H) ; RET ; DISKETA: ; DISK ; SGT: DEFB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH DEFB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH DEFB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH DEFB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH SAT: DEFB 100,127,0,10 VRAM: VIDEO