Deja Vu
#09
13 ноября 1999 |
|
Coding - coding для чайников: как устроен "Boot" изнутри.
(C) SKL-KEEPER aka Колесников Сергей __________________________________________ "Boot" - взгляд внутрь и возможность усовершенствования. В этой своей статье я хочу затронуть тему, которая никогда и нигде не затраги- валась, за исключением ZX-Ревю N:5/1994, да и то очень скупо и лишь вскользь совпа- дающе с названной темой. Там речь шла об автостарте BASIC-строки из машинного кода. Здесь же я хочу остановиться на теме бо- лее широкой, а именно - простейший "boot", как он работает? Самым простым, на мой взгляд, является двухсекторный системный "boot", разрабо- танный ShiSoft в 1993 году. Уж этот-то bo- ot наверняка найдется в коллекции любого спектрумиста. С него и начнем. Мне кажется, я достаточно хорошо разоб- рался с тем, как же он работает, чем и спешу поделиться с коллегами. Итак ... ;Дизассемблер boot SHISOFT-1993 (той час- ;ти, которая перебрасывается в адрес 50015 ;(#C35F) и стартует с него же). ;В BASICе первой строкой стоит: RANDOMIZE ;USR VAL "15619":REM: SAVE "boot " LINE ;VAL "2" ;Второй строкой стоит: RANDOMIZE USR VAL ;"23923" ;LOADER представляет из себя следующее: ; ORG 23923 ; ; PUSH HL ;Обязательно надо ; ;сохранить HL на ; ;стеке!!! ; LD HL,METKA ;Откуда брать. ; LD DE,50015 ;Куда переносить. ; LD BC,556 ;Сколько байт. ; LDIR ;Перенос. ; JP 50015 ;Старт программы. ;METKA DEFS 556 А вот, наконец, и сам дизассемблер boot'а: ORG #C35F BEGIN LD A,#07 LD (#5C09),A ;Установка ве- ;личины задер- ;жки между на- ;жатием кл. и ;автоповтором. LD (#5C0A),A ;Устан.периода ;автоповтора. ;Эти установки необходимы для более удоб- ;ной работы клавиатуры. Она должна в нашем ;случае сразу реагировать!.. CALL ATTR ;Вызов п/прогр. ;устан.аттриб. ;и CLS. XOR A LD (VAR_1),A ;Обнуление пе- ;ременных. LD (VAR_2),A LD (NPROG),A OUT (#FE),A ;BORDER 0. LD D,A ;Нулев.дорожка. LD E,A ;Нулев.сектор. LD BC,#0805 ;Читать 8 сект. LD HL,BUFER ;Адрес буфера, ;куда читаем ;каталог диска. CALL #3D13 LD IX,BUFER ;В IX-начало ;буфера,где на- ;ходится счи- ;танный каталог LD DE,BUFER+#800 ;В DE-адрес бу- ;фера,где будет ;каталог BASIC- ;программ. LAB_1 LD A,(IX+#00) ;Адрес 1й прог- ;раммы в катал. OR A JR Z,TEXTP ;Если 1й символ ;файла=0,то ;больше файлов ;нет,это по- ;следний и идем ;на метку ,где ;печатается над ;пись внизу эк- ;рана. CP #01 JR Z,LAB_2 ;Если 1й символ ;=1,то это стер ;тый файл,пере- ;ход на LAB_2. LD A,(IX+#08) ;В аккум.-адрес ;типа файла. CP "B" ;Это BASIC? JR Z,LAB_3 ;Если да,то пе- ;реход по метке LAB_2 PUSH IX ;П/программа POP HL ;расчета адреса LD BC,#0010 ;перехода к сле ADD HL,BC ;дующему назв. PUSH HL POP IX JR LAB_1 ;Зацикливаемся. LAB_3 PUSH IX ;Подпрограмма ;переноса назв. ;прогр. в буфер POP HL LD BC,#0008 ;Длина хазвания ;- 8 байт. LDIR ;Перенесли его. LD HL,NPROG ;В ячейке NPROG ;считаем кол-во ;BASIC-файлов. INC (HL) ;Увеличиваем на ;единицу. JR LAB_2 ;Возвращаемся к ;началу. ;Подпрограмма печати надписи внизу экрана. ;"SHISOFT-93": TEXTP LD (DE),A ;В аккумуляторе ;сейчас ноль. INC A ;Прибавим "1". LD (#5C3C),A ;Установка нул. ;бита этой сис. ;перем.означает ;вывод на слу- ;жебный экран. LD A,#16 ;Начин.печатать RST #10 ;AT ... XOR A RST #10 ;0,... LD A,#09 RST #10 ;9... LD B,#0D ;В "B" - длина ;надписи. LD DE,TEXT_ ;В DE-ее адрес. CYCL1 LD A,(DE) ;Берем 1ю букву RST #10 ;Печатаем ее. INC DE ;Переход к сле- ;дующей букве. DJNZ CYCL1 ;Зацикливаемся, ;пока все не ;напечатаем. LD A,#02 ;Открывается CALL #1601 ;канал экрана LD A,#15 ;OVER ... RST #10 LD A,#01 ;1 ... RST #10 LD DE,BUFER+#800 ;В DE заносится ;адрес буфера, ;где находятся ;BASIC-файлы. LAB_4 LD C,#03 ;Три колонки. CYCL3 LD A,(DE) OR A ;Не ноль? JR Z,LAB_6 ;Если да, то ;пошли на LAB_6 LD A,#20 ;Пробел. RST #10 ;Напечатали... LD B,#08 ;Длина названия ;программы. CYCL2 LD A,(DE) ;Печать этого RST #10 ;названия. INC DE DJNZ CYCL2 ;Пока не напе- ;чатаем. LD A,#20 ;Печать пробела RST #10 DEC C JR NZ,CYCL3 LD A,#0D ;Код 13 - конец RST #10 ;строки. JR LAB_4 ;Повторим снова LAB_5 LD A,(VAR_2) CALL LAB_7 LAB_6 LD A,(VAR_1) CALL LAB_7 JR KLAWA LAB_7 LD B,#00 CYCL4 CP #03 ;Три столбика? JR C,LAB_8 ;Если меньше, ;пошли к LAB_8. SUB #03 ;Иначе вычитаем ;тройку и на 1 INC B ;увелич.рег."B" JR CYCL4 ;Зацикливаемся. ;А в нижеследующей подпрограмме произво- ;дится расчет месторасположения печати: LAB_8 SLA A ;Арифм.сдвиг ;влево. LD C,A ;Запомним это в ;регистре "C". SLA A ;Еще пару раз SLA A ;сдвиг влево. ADD A,C ;Складываем с ;тем,что в "С". LD C,A INC C LD A,#16 ;AT... RST #10 LD A,B ;Расчет позиции RST #10 ;печати (колон- LD A,C ;ка, строка). RST #10 LD A,#14 ;INVERSE... RST #10 LD A,#01 ;1... RST #10 LD B,#08 ;Длина названия CYCL5 LD A,#20 ;Пробел RST #10 ;Печать пробела DJNZ CYCL5 RET ;Подпрограмма опроса клавиатуры: KLAWA LD A,(VAR_1) ;В этих ячейках LD (VAR_2),A ;-данные о поло- ;жении курсора. LD HL,#5C3B ;В HL-адрес пе- ;рем.FLAGS. 5й ;бит ее устанав ;ливается при ;нажатии любой ;символ.клавиши RES 5,(HL) ;Сброс 5 бита. HALT ;Ждем след.прер. BIT 5,(HL) ;Проверка 5 бита JR Z,KLAWA ;Если клав. нажа ;ли,команда "про ;скакивается". LD A,(#5C08) ;Заносим в A со- ;держимое LAST_K CP #0D ;Это ENTER? JP Z,PUSK_ ;если нет,коман. ;проскакивается. SET 5,A ;Установ. 5 бит. CP "6" ;Это "6"? JR Z,WLEWO CP "7" ;Это "7"? JR Z,PRAWO CP "8" ;Это "8"? JP Z,WNIZ_ CP "9" ;Это "9"? JR Z,WWERX CP #30 ;Это ноль? JP Z,PUSK_ CP #6F ;Это буква "о"? JP Z,WLEWO CP #70 ;Это "p"? JP Z,PRAWO CP #71 ;Это "q"? JP Z,WWERX CP #61 ;Это "a"? JP Z,WNIZ_ CP #20 ;Это пробел? JP Z,BEGIN CP #63 ;Это буква "c"? JP Z,AGAIN WLEWO LD HL,VAR_1 LD A,(HL) OR A JR Z,KLAWA DEC (HL) JP LAB_5 PRAW LD A,(NPROG) DEC A LD HL,VAR_1 CP (HL) JP Z,KLAWA INC (HL) JP LAB_5 WWERX LD HL,VAR_1 LD A,(HL) OR A JP Z,KLAWA DEC A OR A JP Z,KLAWA DEC A OR A JP Z,KLAWA DEC A LD (HL),A JP LAB_5 WNIZ_ LD A,(NPROG) LD HL,VAR_1 CP (HL) JP Z,KLAWA DEC A CP (HL) JP Z,KLAWA DEC A CP (HL) JP Z,KLAWA DEC A CP (HL) JP Z,KLAWA INC (HL) INC (HL) INC (HL) JP LAB_5 ;Если будет нажат ENTER, то после неболь- ;шой подготовки запускаем выбранную прог- ;рамму: PUSK_ LD A,#15 ;OVER ... RST #10 XOR A ;0 ... RST #10 LD A,#38 ;Новые аттрибуты CALL ATTR LD A,#07 ;Белый BORDER. OUT (#FE),A LD A,(VAR_1) ;Начинаем расчет ;номера запуск. ;программы. RLC A ;Вращ.влево без RLC A ;флага переноса. LD C,A LD B,#00 LD HL,BUFER+#800 ADD HL,BC ADD HL,BC LD DE,#5D4E ;Место в 1й ст- ;робе BASICа,где ;наход. название ;"boot ". LD BC,#0008 ;Длина названия LDIR ;Перенос в BASIC ;-строку. LD A,#3A ;Это-двоеточие. LD (#5D57),A ;Перенос его в ;BASIC-строку. LD A,#F7 ;Это - RUN. LD (#5D4C),A ;Перенос его в ;1ю BASIC-строку ;вместо SAVE. AGAIN XOR A ;Обнуляем аккум. LD (#5C42),A ;Занесли 0 в пе- LD (#5C44),A ;ременные,где ;номер строки ;BASIC следующ. ;оператора и ;номер след.вы- ;полняемого опе- ;ратора RASIC. LD HL,#0223 ;Возвратим изме- LD (#5C09),HL ;ненные в начале ;boot-а перемен- ;ные. POP HL ;Сохран.на стеке RET ATTR LD (#5C8D),A ;Постоянные атт- ;рибуты. LD (#5C48),A ;Аттриб.служебн. ;экрана. CALL #0D6B ;CLS RET TEXT_ DEFB "1993 ShiSoft" NPROG DEFB 0 ;Колич.BASIC- ;программ. VAR_1 DEFB 0 VAR_2 DEFB 0 BUFER DEFB 0 ;Отсюда начина- ;ется каталог ;диска. Ну вот, разобрались, как он работает. Надеюсь, всем все понятно? Перейдем ко второй части моего по- вествования...:-) Итак, есть ли у этого boot'а недостат- ки? Да их всегда можно найти, было бы же- лание:-) Ну, например, зачем нам надо вы- водить на экран сам "boot", если мы его можем перезапустить нажатием пробела? И еще: есть программы, состоящие из двух BA- SIC-загрузчикое. В этом случае второй заг- рузчик нам не нужен, он будет только пута- ницу вносить, и его желательно бы не выво- дить... Значит, первая задача такова: включить в программу "boot"'а фильтрование всех BA- SIC-файлов, начинающихся с маленькой буквы или с пробела (это уже на всякий случай). Как это сделать? Очень просто: включить в дизассемблер следующий фрагмент: ................... CP #01 JR Z,LAB_2 ;Если 1й символ ;=1,то это стер ;тый файл,пере- ;ход на L399. CP " " ;Это пробел? JR Z,LAB_2 ;Если да, пере- ;ход по метке. CP #5B ;если >="Z",то JR NC,LAB_2 ;переход, т.к. ;после "Z" идут ;маленьк.буквы. LD A,(IX+#08) ;В аккум.-адрес ;типа файла. CP "B" ;Это BASIC? JR Z,LAB_3 ;Если да,то пе- ................... Куда этот фрагмент включить, я думаю, Вы поняли (я специально оставил по две строчки сверху и снизу из основной прог- раммы. Далее... Наверное, более убобно для пользователя будет,если шрифт, которым вы- водится названия программ, будет не стан- датным Спектрумовским, а "покрасивше". По- жалуйста, вот Вам еще фрагмент (процедура формирования шрифта вытащена мной из прог- раммы MINIBOOT 3.0: ну, уж очень понравил- ся шрифт!): ................. LD (#5C0A),A CALL ATTR ;Вызов п/прогр. ;устан.аттриб. ;и CLS. LD HL,15360 LD DE,FONT PUSH DE LD (23606),DE LD BC,1024 LDIR POP HL LD BC, 128 LAB2 PUSH BC INC HL INC HL INC HL LD B,3 LAB1 LD D,(HL) LD A,D RLA OR D LD (HL),A INC HL DJNZ LAB1 POP BC DEC BC INC HL INC HL LD A,B OR C JR NZ,LAB2 .............. Только надо не забыть,что когда мы сде- лали выбор программы и нажали ENTER для запуска, необходимо вернуть значения CHARS (в подпрограмме PUSK_): ................. LD A,#38 CALL ATTR LD HL,15360 LD (23606),HL LD A,#07 ................ Ну, и последнее. Как известно, в описы- ваемом boot'е управлять курсором можно с помощью правого Синклер-джойстика и клави- шами QAOP,SPACE. Можно добавить еще опрос курсорных клавиш (в подпрограмму с прият- ным названием KLAWA). Как это сделать, Вы можете прочесть в моей статье об опросе клавиатуры в разделе для "чайников" DEJA VU.
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября