 |
К оглавлению разделов
Palm OS Emulator
07.03.2004 Эмулятор PalmOS — это программа, которая, как можно додуматься, дозволяет эмулировать работу PalmOS не на Palm (к примеру, Pilot 1000, Pilot 5000, PalmPilot, и Palm III) на настольном ПК в среде Windows либо Macintosh. Он дозволяет очень много и корректно Эмулятор PalmOS — это программа, которая, как можно додуматься, дозволяет эмулировать работу PalmOS не на Palm (к примеру, Pilot 1000, Pilot 5000, PalmPilot, и Palm III) на настольном ПК в среде Windows либо Macintosh. Он дозволяет очень много и корректно эмулировать аппаратные средства, которые употребляются как база для платформы Palm Computing, а не считая того, имеет несколько функций, которые полезны разрабам ПО для отладки программ, рассчитанных на PalmOS.
Эмулятор PalmOS вначале создавался как инструментальное средство для разрабов, хотя его запустить может каждый юзер. Это значит, что вы сможете, к примеру, поиграть в свою возлюбленную игру для Palm на ПК с Windows либо Macintosh.
Сначала было...
Эмулятор PalmOS начал жизнь как UN*X Amiga Emulator (UAE), который был разработан Берндом Шмидтом в Германии (www.freiburg.linux.де/~uae). И ПК серии Commodore Amiga и органайзеры Palm основаны на ЦП серии 680x0, так что начальная программа эмуляции ЦП процессора для UAE была применена как база для подсистемы эмуляции процессоры в CoPilot.
Посреди 1996 г. Грег Хьюджилл (www.hewgill.com) начал работы над проектом CoPilot, используя UAE как базу для эмулятора. К ядру подсистемы эмуляции ЦП 68000 он добавил поддержку ЦП 68328 Dragonball, который применялся в Palm, и остальных аппаратных средств Palm.
В сентябре 1996 г он выпустил первую бета-версию CoPilot 1.0. Со временем он дорабатывал програмку, добавляя новейшие функции, и воплотил возможность работать с наиболее поздними версиями PalmOS, окончив работу над проектом с созданием CoPilot 1.0 b9, которая была размещена посреди 1997 г. [дополнительную информацию о этом проекте можно отыскать в работе Грега «CoPilot: проект и Разработка», прим. ред.]
CoPilot отчаливает в путь
Грег был заинтересован в том, чтоб его работа приносила пользу очень вероятному количеству разрабов и в октябре 1996 г. он опубликовал начальные тексты CoPilot на собственном Web-узле. Он предложил хоть какому разрабу возможность перенести CoPilot на остальные платформы, и его предложение было принято. CoPilot сейчас перенесен на Macintosh (две версии), Linux, BeOS, OS/ 2 и даже Windows CE.
Palm протягивает руку
В декабре 1997 г. я оставил группу разработки Newton и перебежал в Palm Computing, в качестве инженера в группе средств разработки. Я был вторым сотрудником в данной группе и мне было что делать. Одной из этих задач было адаптировать CoPilot для разработки нашего грядущего продукта — Palm III. На самом деле дела, CoPilot необходимо было переработать так, чтоб он мог работать с ПЗУ, размером наиболее 1 Мбайт, экраном с градациями сероватого, емкой динамической памятью и обработку новейших регистров Dragonball, которые мы использовали.
Работая с начальными текстами CoPilot 1.0b9 и с начальными текстами версии для Macintosh, которые предоставила компания Illume Software (members.aol.com/illumesoft/illume.html), индивидуальности были довольно быстро реализованы и стали доступны разрабам для PalmOS.
CoPilot преобразуется в PalmOS Emulator
Переделывая CoPilot в рамках проекта Palm III, мы сообразили, что эта программа имеет большой потенциал. До того момента, Palm предлагала для разработки программ на ПК воспользоваться Palm Simulator, набор библиотек для CodeWarrior, которые дозволяли компилировать из одних и тех же начальных текстов программы для Macintosh и Palm OS. Создатели делали свою програмку для PalmOS, компоновали с библиотеками Simulator, которые дозволяли запускать програмку для PalmOS в среде Macintosh, запускали и отлаживали ее как обыденную програмку для Macintosh.
Способ предоставлял несколько преимуществ — к примеру, малая продолжительность цикла «редактирование-компиляция-отладка», возможность отладки на уровне начальных текстов на языках высочайшего уровня, скорость программы и возможность сотворения «ознакомительных версий» программы, которые юзер мог «посмотреть» на ПК. Но, он был связан и с недочетами — к примеру, подготовка и отладка 2-ух версий — имитатор не обеспечивал полную эмуляцию Palm и, очевидно, необходимость иметь Macintosh. Мы поразмыслили, что было бы верно объединить достоинства Simulator и CoPilot, создав вправду массивное средство разработки для PalmOS, которое могло бы работать на различных платформах.
Мы побеседовали с Грегом Хьюджиллом, (создатель CoPilot для Windows), Крейгом Шеффилдом из Illume Software и Шмидтом Берндом (создателем UAE и ядра подсистемы эмуляции ЦП 68000) и договорились о разрешении продолжать разработку CoPilot, используя их работу как базу для разработки эмулятора PalmOS. Они поддержали нашу разработку наиболее сильной версии эмулятора, в особенности когда мы объявили, что начальные тексты будут доступны всем разрабам.
Не считая того, в это время Palm Computing приняла решение о переходе на новейшую марку. PalmPilot стал Palm III, PilotDebugger — PalmDebugger, CoPilot перевоплотился в эмулятор PalmOS (PalmOS Emulator). В данной материале я буду обозначать заглавием CoPilot 1-ые версии, разработанные Грегом, а «эмулятор PalmOS» — версии, которые сделала Palm Computing.
Новейшие способности
Опосля того, как были урегулированы юридические тонкости, мы начали переделывать програмку. В данной статье вы отыщите короткое обсуждение этих переделок.
Общественная база начальных текстов
Каждый разраб имеет свой стиль программирования: Бернд, Грег и Крейг все работали по-разному. Когда Крейг переносил эмулятор из Windows на Macintosh, он кое в чем облагораживал и так красивый эмулятор, разработанной Грегом. Он изменил оформление начальных текстов, употреблял наиболее описательные имена функций и переменных, добавив комменты. Когда он завершил работу, портированная им версия CoPilot была функционально эквивалентна версии для Windows, но была реализована незначительно не так.
Первой задачей было объединить начальные тексты обеих программ. Так как я собирался разрабатывать и поддерживать редакции для Windows и для Macintosh, я решил, что будет верно иметь возможность синхронно развивать PalmOS Emulator для всех платформ.
В итоге, я объединил начальные тексты, так, что 93 процента начальных текстов были схожи (не считая начальных текстов, приготовленных в PowerPlant для Macintosh).
Свежайшие начальные тексты UAE
С того времени как Грег употреблял начальные тексты UAE в качестве базы для CoPilot посреди 1996 г., Бернд продолжал изменять UAE, окончив на версии 0.69, которую опубликовал в мае 1997 г. Так как я уже поигрался с начальными текстами, объединяя версии для различных платформ, я также решил корректировать и начальные тексты подсистемы эмуляции ЦП, использовав свежайшие начальные тексты UAE. Это позволило поправить несколько ошибок, не считая того, конфигурации, которые делал Бернд, предоставили возможность прирастить скорость работы подсистемы, которая эмулировала ЦП.
Установка огромных программ
Вначале, одна из главных заморочек CoPilot состояла в невозможности загружать программы либо базы данных из файлов, размером наиболее 64 Кбайт. Причина — способ, который употреблялся в CoPilot для загрузки программы. CoPilot работал так:
выделял особый сектор памяти (по существу, добавлялось 64 Кбайт памяти к эмулируемому ОЗУ PalmOS);
оформлял его как 64-Кбайт блок (chunk) памяти (подобно тому, как работает функция MemPtrNew, когда вы выделяете для себя память);
переносил туда содержимое файла PRC либо PDB; и
инициировал вызов DmCreateDatabaseFromImage.
Неувязка этого способа — он связан с необходимостью выделения кусочка памяти способами, совместимыми с MemPtrNew. В PalmOS OS 1.0 и 2.0 блок памяти не могли превосходить 64 Кбайт. Внедрение этого способа означало к тому же трудности сопоставимости с PalmOS 3.0, где заголовок блока памяти занимал не 6 б, а восемь. Этот прием просто не работал бы, когда CoPilot запускался бы с PalmOS 3.0.
Сейчас употребляется другой способ. Заместо пуска DmCreateDatabaseFromImage, функциональность DmCreateDatabaseFromImage реализована в эмуляторе PalmOS. Когда юзер инсталлирует файл PRC/PDB, то создается новенькая БД, основываясь на инфы, содержащейся в заголовке файла, из файла считываются составляющие ЬЛ PalmOS и записываются в области ОЗУ БД эмулятора. Используя эту технику, эмулятор PalmOS закончил быть ограничен 64-Кбайт блоком памяти и закончил быть связан с форматом либо размером заголовка блока памяти.
Наружный отладчик
Одно из преимуществ Palm Simulator в Macintosh — возможность работы с отладчиком, который дозволяет отлаживать программы на языке высочайшего уровня при разработке программы. По контрасту, редакция CoPilot для Windows имела лишь возможность отладки ассемблерных текстов при помощи отладчика, работающего в режиме командной строчки, версия CoPilot для Macintosh не содержала отладчика.
В феврале 1998 г. мы пригласили Эрика Клонингера из Portable Computing Products, Марка Корри из Metrowerks и Кеннета Альбановски из Silver Hammer Group посетить нас, посмотрев на бета-версию PalmOS 3.0. Мы планировали побеседовать о способности интеграции эмулятора PalmOS и остальных отладчиков (к примеру, отладчик Metrowerks и gdb).
На момент подготовки данной статьи (март 1998 г.) в целом поддержка наружных отладчиков работала. Подготовительная версия Metrowerks Debugger позволяла отлаживать исходыне тексты программ, работающих на эмуляторе PalmOS. Наша тестовая версия «вскрытого» отладчика PalmDebugger позволяла отлаживать программы на ассемблере. аппликации на машинном языковом уровне. Скоро мы передадим начальные тексты Silver Hammer Group, которые они употребляют для адаптации редакции CoPilot для UNIX и пакетов gcc/gdb. Мы предоставим их и компании SoftMagic (разраб программы Satellite Forms) и иным создателям инструментальных средств для PalmOS.
Гремлины
Одним из преимуществ, которые имели создатели, работавшие на Macintosh — набор утилит, которые не были доступны в редакции SDK для Windows. Какой-то из них — «Гремлины». Это подпрограмма, которая пересылает серию псевдослучайных событие в очереди событий программы для PalmOS, что дозволяет имитировать нагрузку, которую не способен сделать юзер. Ежели в програмке есть ошибка, то серия событий, которая дозволила ее найти быть может воспроизведена, позволяя разобраться с неувязкой. Гремлины были реализованы в PalmDebugger и в Simulator, что делало неосуществимым внедрение такового полезного средства на остальных платформах.
Эмулятор PalmOS был расширен, и в нем завелись «Гремлины». Запуская новейшего «Гремлина» из пт меню, юзер мог выбрать несколько режимов:
номер (определял характеристики инициализации генератора псевдослучайных чисел);
количество псевдослучайных событий, которые передаются в програмку;
программа, которую необходимо тестировать; и
характеристики записи событий в журнальчик.
Реализация «Гремлинов» в редакции эмулятора PalmOS для Windows дозволила почти всем разрабам принять роль в програмке сертификации свойства программ.
Скорость
Проверяя, какие достоинства Simulator можно воплотить с эмуляторе PalmOS, мы отыскали одно, которое было нереально перенести в POSE — скорость. Программы, сделанные при помощи библиотек симулятора — полнофункциональные программы для Macintosh, которые работают с наибольшей скоростью, которую лишь можно воплотить для ЦП PowerPC. Работа программы в среде PalmOS на виртуальном процессоре эмулятора, где любая машинная команда порождает пуск подпрограммы, которая записывает информацию в «регистры» и имитирует доступ к памяти. Даже на массивных моделях ПК, скорость работы эмулятора — приблизительно 2 млн. аннотация ЦА Dragonball в секунду. Эта скорость приблизительно соответствует скорости работы настоящего Palm, но она в 10-ки раз меньше, ежели работа программы на ПК.
Я использовал два способа для ускорения работы POSE по сопоставлению с CoPilot. 1-ый способ основан на основном принципе ускорения: ежели функция работает очень долго, сделайте ее скорее. Используя этот способ, я нашел множество мест, которые могли бы быть ускорены на несколько процентов. Не считая того, для ускорения POSE я употреблял способ оптимизации, который мы применяли при разработке Newton: возьмите функцию, которая быть может логически разбита на несколько подпрограмм, для каждой из которой определяется частота запусков, после этого те, которые необходимы не повсевременно переносили в собственные функции, упрощая основную функцию. Итог — наиболее малогабаритные функции компилятор может эффективнее улучшить. Итог таковой оптимизации — ускорение приблизительно на 20%.
Употреблялся и иной принцип оптимизации: ежели подпрограмма работает долго, не применяйте. На практике это значит, что для вас придется поменять методы, кэшируя промежные результаты и используя эмпирические познания о работе программы. Но в случае эмулятора PalmOS, мы можем применять подход, связанный с имитацией ОС, заместо «полноценно» эмуляции, заменив исконные функции, наиболее высокоскоростными. В качестве примера можно отметить менеджер системных исключений. Когда PalmOS запускает системную функцию, скажем, MemPtrNew либо DmCreateDatabase, компилятор задает в машинный код аннотацию TRAP $F, передавая идентификатор формы $Axxx. Когда программа запускает эту аннотацию, ЦП генерирует аппаратное исключение, заносит в стек счетчик команд и регистр статуса и перебегает по адресу в нижней памяти, который хранится в векторе прерывания. PalmOS передает подсистеме обработки исключений адресок этого вектора. Таковым образом, когда системное исключение TRAP $F, выполняется, запускается подсистема обработки прерываний. Эта подпрограмма потом употребляет значение счетчика команд из стека, употребляет его для подборки адреса очередной аннотации прикладной программы, которая расположена опосля аннотации TRAP и употребляет номер начального адреса, чтоб передать позже выполнения на адресок в ПЗУ.
Процедура не чрезвычайно долгая, но она занимает определенный период, при этом, это происходит каждый раз, когда запускается функция PalmOS (также когда функция ПЗУ запускает другую функцию в ПЗУ). Проще говоря, это происходит нередко.
Для ускорения, я воплотил несколько особых алгоритмов, основанных на эмпирическом знании о работе PalmOS, когда она запускает функции. В принципе, это обход подсистемы управления прерываниями в эмуляторе и реализация данной операции своими руками. Сейчас, когда эмулятор PalmOS сталкивается с аннотацией TRAP $F, заместо сложного пути условных переходов и использования функция подсистемы управления прерываниями, она реализует эту функцию на базе «подлинных» команд ЦП ПК. POSE:
записывает счетчик команд, который был передан в стек;
употребляет счетчик команд, выбирая адресок аннотации, которая будет расположена за аннотацией TRAP $F;
описывает массив указателей на функции ПЗУ, размещенные в нижней памяти;
записывает указатель на подходящую функцию, основываясь на номере прерывания;
передает управление функции, изменяя счетчик команд.
Эмулятор PalmOS работает по этому методу, заменяя эмулируемые аннотации обработчика прерываний своими, стремительными, работающими на ЦП ПК. Скорость была увеличена на 12 процентов.
Для роста производительности функций ПЗУ, связанных с копированием областей памяти применялся новейший прием. Подпрограммы MemSet, MemMove и RctPtInRectangle — нередко используемые — были реализованы на базе инструкций ЦП ПК, в POSE, а при помощи эмуляции «родных» функций PalmOS.
Журнальчик
Так как мы рассчитывали сделать POSE полезным разрабам, то было надо предоставить информацию о работе программы, которая могла быть полезна для разработки. Более популярная неувязка в случае сбоя программы проста — что вообщем вышло? В 90% случаев, первопричина трагедии размещается, мягко говоря, не близко к месту, где ошибка проявилась. С способностями записи инфы, которые были реализованы в эмуляторе PalmOS, создатели могли изучить журнальчик событий, который происходили перед ошибкой. Разраб может просмотреть действия в очереди событий программы и те, которые программа обрабатывала. Он может просмотреть перечень вызовов функций ПЗУ. В конце концов, он может просмотреть дамп памяти в виде ассемблерного листинга, до ошибки.
Ежели я вдохновлюсь, то в одном из будущих версий, добавлю возможность «отката», так, чтоб все состояние эмулятора было зафиксировано и равномерно отменено, чтоб разраб мог изучить в «замедленном режиме» действия и функции, которые происходили перед ошибкой.
Управление памятью
1-ый момент для реализации прикладной программы — осознать, что она работает в дружественной среде. Другими словами, необходимо осознать, что программа работает и работает как следует, реагируя и на предполагаемые и на нежданные действия. Потом нужно проверить, как она работает в негостеприимной среде. Эмулятор PalmOS дозволяет это сделать и даже предоставляет несколько огромные способности. К примеру, эмулятор контролирует динамическую память, когда программа завершается, определяя утечки памяти. Обнаружив делему, POSE выдает сообщение. Либо, к примеру, POSE дозволяет найти неправильную работу со стеком, когда подпрограмма возвращает управление вызывающей функции, стек ниже текущего указателя вершины очищается, что упрощает поиск ошибок, связанных с внедрением данных, которых в стеке уже нет. В конце концов, эмулятор обнаруживает переполнение стека.
Тестируем программы
Palm OS Emulator — это не только лишь инструмент для разрабов. Юзеры программ для PalmOS могут применять его для проверки правильности программ. Palm Computing заинтересована в том, чтоб программы для PalmOS были надежны (для этого и сделаны такие инструментальные средства, как «Гремлины» и программы сертификации ПО). В PalmOS Emulator были реализованы средства, с которыми можно отловить ошибки, может быть, не проявляющиеся на современных моделях, но которые могут «всплыть» в будущих. POSE инспектирует доступ к нижней памяти, регистрам ЦП, видеопамяти. Попытка программы применять какой-нибудь неправильный прием будет обозначена предоставлением юзеру инфы о нарушении програмкой советов про разработке для PalmOS (следовать советам по разработке для PalmOS — верная мысль, отладчик PalmOS инспектирует некие неправильные деяния и в дальнейшем их, наверняка, будет больше; см. «Руководящие принципы для разработчиков»).
Так как POSE инспектирует ПО, юзер может инсталлировать програмку, к примеру, скопированную из Веб, запустить их на эмуляторе PalmOS и проверить, как они работают и нет ли заморочек при интенсивной работе. Ежели программа работает, юзер знает, что покупка данной программы — отменная растрата средств.
Прочее
Мы проектируем много новейших функций, к примеру, загрузка файлов ПЗУ и сеансов просто «перетаскиванием». В каталоге AutoLoad можно будет расположить файлы, которые автоматом будут загружаться в POSE при запуске эмулятора. Синхронизация с Palm Desktop, профилировщик программ, который дозволяет упростить оптимизацию, возможность «отката», когда POSE сохранит состояние ЦП и памяти (так то, их можно будет вернуть в хоть какой момент) — это и почти все другое.
Внутренняя организация POSE для Windows и Macintosh разрабатывалась на базе UAE и CoPilot. Для разрабов, которые интересуются, как POSE работает, мы подготовили обзор, который идет ниже.
Эмулятор ЦП
Я упомянул ранее, что 93% начальных текстов POSE разделяется меж версиями для Windows и Macintosh. Крупная половина в этих 93% принадлежит подсистеме эмуляции ЦП. Эмулятор ЦП прост: считываем код операции из памяти и исполняем его. Практически, вот отрывок из цикла эмуляции ЦП в POSE:
while (gCPUState == kCPUState_ Running)
{
uae_ u32 opcode = nextiword ();
(* cpufunctbl[opcode]) (opcode);
}
Этот обрезок реализует обычный метод, который приводится выше: выбирается функцией nextiword код операции из ячейки памяти, данной в регистре PC, потом употребляет этот код операции как индекс в таблице 65,536 указателей, по которым выбирается адресок и подпрограмма обработки аннотации.
Но эмулятор ЦП в то же время чрезвычайно сложен — есть масса кодов операций и много маленьких деталей, которые нужно учесть, эмулируя их. Конфигурации статусных битов, работа с памятью необходимо проверить и воплотить, обработать неординарные ситуации, прерывания, работу супервизора, условные операторы обработаны — довольно, чтоб свести разраба с разума.
Я уверен, Бернрд Шмидт мыслил так же. 1-ая версия UAE (версия 0.1, доступная на упомянутом до этого Web-узле USE) было кропотливо проработанным вручную эмулятором. Потому что разработка UAE длилась, Бернрд воплотил идею «компилятора эмулятора» ЦП.
Этот компилятор работает с маленькими текстовыми файлами, содержащими описание всех кодов операции 680x0. Потом, он употребляет информацию из их для генерации обработчиков кодов операций. Итог: 16 файлов начальной программы, содержащих тыщи обработчиков инструкций ЦП и иной файл, содержащий большой массив cpufunctbl, с указателями.
Вот вам наглядный пример:
1101 rrr0 zzss sSSS: 00: XNZVC:NN: ADD. z s, Dr
Это запись файла описания ЦП для машинной аннотации ADD. Слева находиться описание битов кода операции: 0 и 1 интерпретируются как значения для регистра счетчика команд, z — представляет размер регистра, s — биты типа адресации. Последующее биты описания коды операции задают ЦП на котором код операции должен работать (00 — ядро 68000, прямой потомок которого — Dragonball). Потом описывается внедрение регистра статуса. Крайний код задает способ адресации операндов.
Вот вам наглядный пример функции, которая создается по шаблону данной операции:
void REGPARAM2 CPU_ OP_ NAME(_ d000)( uae_ u32 opcode)
/* ADD */
{
uae_ u32 srcreg = (opcode & 7);
uae_ u32 dstreg = (opcode >> 9) & 7;
{{ uae_ s8 src = m68k_ dreg( regs, srcreg);
{ uae_ s8 dst = m68k_ dreg( regs, dstreg);
{{ uae_ u32 newv = (( uae_ s8)( dst)) + (( uae_ s8)( src));
{ int flgs = (( uae_ s8)( src)) < 0;
int flgo = (( uae_ s8)( dst)) < 0;
int flgn = (( uae_ s8)( newv)) < 0;
ZFLG = (( uae_ s8)( newv)) == 0;
VFLG = (flgs == flgo) && (flgn != flgo);
CFLG = XFLG = (( uae_ u8)(~ dst)) < (( uae_ u8)( src));
NFLG = flgn != 0;
m68k_ dreg( regs, dstreg) =
(m68k_ dreg( regs, dstreg) & ~0xff) | (( newv) & 0xff);
}}}}}}}
Эта функция извлекает начальные и мотивированные регистры, закодированные в 3-х первых битах кода операции (соответственных параметру SSS в описании кода операции в файле определений), потом мотивированные регистры (закодированные в 3-х битах RRR в описании аннотации). Потом значения регистров считываются (массив из 16 целочисленных переменных предусматривается в эмуляторе ЦП). Две величины складываются, биты регистра статуса меняются, новенькая величина сохранена в мотивированном регистре.
Обращение к ОЗУ
Дополнительно к приемам оптимизации, которые рассматривались выше, нужно увидеть, что необходимо иметь в виду правило «скорость против размера». Часто вы сможете уменьшить свои функции и уменьшить методы, но традиционно при всем этом миниатюризируется скорость работы. Равно справедливо и обратное: вы сможете убыстрить програмку, позволяя ей съесть столько памяти, сколько она сумеет (до того времени, пока вы не достигнете точки, где дисковая активность, порожденная работой ОС с виртуальной памятью фактически приостановит вашу програмку).
Функция cpufunctbl, которую мы разглядывали в разделе, посвященном основному циклу эмуляции ЦП — практический пример. Используя 256-Кбацт таблицу, которая содержит 64 указателя, мы можем обрабатывать аннотации ЦП, быстро передавая указатели подходящим подпрограммам. И обращение к ОЗУ работает приблизительно так же. Адресное место в 4 Гбайт разделяется на 65,536 частей ("банк» в начальных текстах UAE), каждый по 64 Кбайт. Любой из этих банков доступен при помощи особых функций. Когда нужно считать информацию из «ОЗЦ», PalmOS Emulator употребляет верхние 16 битов адреса (номер банка) как индекс на 64-Кбайц таблицу. Любая запись в ней — четырехбайтовый указатель на набор функций, управляющих сиим банком. PalmOS Emulator потом извлекает функцию, пригодную для подходящего деяния и запускает ее.
Обычный пример объясняет это описание. Допустите что мы обращаемся 1-ые два банка (1-ые 128 Кбайт из 4-Гбайт адресного места) как к обыкновенному ОЗУ. Поначалу, мы создаем набор функций, чтоб разглядывать кусочек памяти как область памяти с прямым доступом:
uae_u32 RAMBank_GetLong (uaecptr iAddress)
{
return do_get_mem_long((
(char*) gRAM_Memory) + iAddress);
}
uae_u32 RAMBank_GetWord (uaecptr iAddress)
{
return do_get_mem_word(
(( char*) gRAM_Memory) + iAddress);
}
uae_ u32 RAMBank_ GetByte (uaecptr iAddress)
{
return do_ get_ mem_ byte(
(( char*) gRAM_ Memory) + iAddress);
}
void RAMBank_ SetLong (uaecptr iAddress, uae_ u32 iLongVal-ue)
{
do_ put_ mem_ long(
(( char*) gRAM_ Memory) + iAddress, iLongValue);
}
void RAMBank_ SetWord (
uaecptr iAddress, uae_ u32 iWordValue)
{
do_ put_ mem_ word(
(( char*) gRAM_ Memory) + iAddress, iWordValue);
}
void RAMBank_ SetByte (
uaecptr iAddress, uae_ u32 iByteValue)
{
do_ put_ mem_ byte(
(( char*) gRAM_ Memory) + iAddress, iByteValue);
}
int RAMBank_ ValidAddress (
uaecptr iAddress, uae_ u32 iSize)
{
int result = (
iAddress + iSize) <= (uae_ u32) gRAMBank_ Size;
assert( result);
return result;
}
uae_ u8* RAMBank_ GetRealAddress (uaecptr iAddress)
{
return (uae_ u8*) &((( char*) gRAM_Memory)[ iAddress]);
}
В функциях:
uae_u32 — беззнаковая 32-разрадная величина (аналогично uae_u16 и uae_u8);
uaecptr — тип UAE для указателей памяти (схожий типу void*);
gRAM_Memory — блок памяти с которой мы распределяем при помощи malloc, когда программа запускается;
do_get_mem_long и проч. — функции. для обхода узеньких мест при работе с памятью.
Опосля того, как поочередная установка функций будет определена, они группируются совместно в структуру данных назвавшую AddressBank:
AddressBank gRAM_Bank =
{
RAMBank_ GetLong,
RAMBank_ GetWord,
RAMBank_ GetByte,
RAMBank_ SetLong,
RAMBank_ SetWord,
RAMBank_ SetByte,
RAMBank_ GetRealAddress,
RAMBank_ ValidAddress
};
Указатель на определенный адресок банка потом заносится в массив из 65,536 указателей AddressBank.
gMemory_ Banks[ 0] = &gRAM_ Bank;
gMemory_ Banks[ 1] = &gRAM_ Bank;
Опосля инициализации массива таковым способом, для доступа к ОЗУ употребляется несколько макросов, которые скрывают детали выбора определенного банка, выбор подходящей функции и ее пуск.
Поддержка Dragonball
Почти все из того, о чем мы говорили пока, было основано на исследовании эмулятора, разработанного Бернрдом Шмидтом. Эта эмуляция дозволяет воплотить общие черты ЦП серии 680x0. Грег Хьюджилл воплотил средства для работы регистров ЦП Dragonball 68328.
В ЦП Dragonball есть набор регистров отображаемых на память, которые созданы для управления некими аппаратными средствами. К примеру, эти регистры можно применять для управления ЖК-экраном, поочередный ввод/вывод, доступ к часам настоящего времени и «предупреждениям». Регистры размешаются в 4-Кбайт области памяти, начинающейся с адреса 0xFFFFF000. Доступ к ним в PalmOS Emulator реализован и контролируется особым набором функций семейства AddressBank. Даже опосля того, как я работал над PalmOS Emulator несколько месяцев, я изумлялся полнотой средств работы с Dragonball, которые воплотил Грег в CoPilot. Не считая базисных средств эмуляции UART, он воплотил возможность работы поочередного ввода-вывода, перенаправляя вызовы API на функции Win32. Изучая примеры битовых масок и работу прерываний, он воплотил средства эмуляции пера, так. что CoPilot превращал координаты мыши информацию о «прикосновениях» на ЖК-дисплее. Задавая значения счетчиков, он смог вынудить PalmOS корректно «засыпать». И он делал это не используя доступ к начальным текстам PalmOS, то, что лично я нахожу очень комфортным, я забываю, как верно нужно задавать тот либо другой бит и пробую сделать нечто с ПЗУ.
Обновление экрана
Естественно, вся эта изнурительная работа бесполезна, ежели мы не можем созидать итог. При работе в среде эмулятора, PalmOS записывает данные в виртуальный буфер ЖК-дисплея, но изменение его содержимого ровненьким счетом ничего не значит исходя из убеждений ПК. на котором работает эмулятор. Нам нужен способ для перемещения содержания видеобуфера в окно ОС ПК.
Способ, использованный в PalmOS Emulator OS тупой, но работает. От 10 до 20 раз в секунду, PalmOS Emulator прерывает работу текущей эмулируемой аннотации ЦП и переключается на подпрограммы прорисовки видеобуфера. При помощи полезной функции memcmpy, не только лишь сравнивается содержимое видеопамяти с тем, что было сохранено в ней до этого, да и корректирует предыдущую копию видеоОЗУ, обновляя ее новеньким содержимым. Итог memcmpy — булево значение, которое указывает, изменялось содержание буфера ЖК-дисплея экрана с того времени как в крайний раз ассоциировали их, либо нет. Ежели это происходило, то содержимое видеопамяти преобразовывается в растровое изображение, которое отображается на экране ПК в окне эмулятора. На 1-ый взор этот способ кажется не чрезвычайно прекрасным. Я задумывался, что лучше будет поменять функции семейства AddressBank, чтоб обнаруживать пробы доступа к видеопамяти, задавать признак «перерисовать экран», при наличии конфигураций в видеоОЗУ. Но это как оказывается, было не настолько отлично, как я поначалу поразмыслил. Функции работы с банками памяти вызываются нередко. Проверка на доступ к видеопамяти как выяснилось, представляет собой наиболее приметную нагрузку, ежели я ждал вначале. Итог — твердый способ оказался достаточно действенным, по сопоставлению с прекрасным. Иной способ, которым я тоже попробовал пользоваться — перехват графических функций и задание признака «перерисовать» в их.
Я избегаю применять в PalmOS Emulator информацию о внутренней структуре PalmOS как может быть; имея таблицу с агрессивно прописываемыми адресами графических функций нарушается этот принцип. Ежели API когда-либо будет изменяться, я был должен бы выпускать новейший эмулятор. Единственный способ, который я мог бы применять еще — пользоваться недокументированной системной функцией ScrDrawNotify. Ежели некая переменная, размещенная в нижней памяти, имеет значение «истина», все графические функции вызывают функцию ScrDrawNotify перед завершением, передавая ей информацию о границах изменившейся области на экране. Я подразумевал, что мог бы задать это значение, прерывать функции чтоб запустить ScrDrawNotify и задавать признак «перерисовать» каждый раз. когда это происходило. Это было теорией. Но, потому что произнес некоторый мудрый человек, «в теории, теория и практика — одно и то же. На практике, это не так». Пока способ с внедрением ScrDrawNotify кажется более продвинутым, но, я не стал его применять по нескольким причинам. Во-1-х, это просит введения в эмулятор особых «знаний» о существовании и размещении данной переменной. Не достаточно того, что она не документирована, ее размещение разнится в PalmOS 2.0 и PalmOS 3.0. Задание признака «перерисовать» работает лишь при использовании программ, работающих лишь с API, и вызывает трудности сопоставимости с програмками, которые работают с видеопамятью. Palm Computing не одобряет таковой практики разработки, но нельзя отрицать факт, что такие программы есть. В конце этих исследований, я решил бросить в покое способ перерисовки, связанный с memcmpy, раз он работает и работает нормально. Профилирование программы указывает, что перерисовка экрана занимает очень не достаточно времени, фактически, на границе точности измерения, так, что фактически нет смысла улучшить его.
Перехват системных функций
Для того, чтоб предоставить возможность ввод данных с клавиатуры и звуковые сигналы, Грег разработал способ перехвата системных функций. Прерывая функцию EvtGetEvent, Грег подставлял в очередь событий запись с данными о нажатых юзером на кнопках в окне CoPilot, оформленными как запись функции EvtGetEvent и передавал итог подпрограмме, которая запрашивала EvtGetEvent. Все, что знала подпрограмма, которая инициировала запрос к EvtGetEvent — вышло событие, структура данных действия заполнена соответствующим образом. Откуда оно взялось и кто его инициировал — какая разница? Аналогично, при помощи перехвата SndDoCmd он перехватывал пробы программ работать с Sound Manager и эмулировал нужные платформно-зависимые операции. Глядя на характеристики переданные функции SndDoCmd, CoPilot вызывал функции звукового API Windows, проигрывая звуки приблизительно так же, как это делает PalmOS.
Способ перехвата функций ПЗУ чрезвычайно прост и основан на технике, которая использовалась при ускорении обработки прерываний. Когда программа вызывает функцию ПЗУ, она выполняет аннотацию TRAP $F. CoPilot прерывает эмуляцию данной аннотации, записывает номер функции, который размещается следом за ней, потом инспектирует необходимо ли нужно ли как-то изменять поведение данной функции. PalmOS Emulator развивает этот способ перехвата системных функций несколько поглубже. Он подменяет некие функции ПЗУ, схожими функциями, но реализованными в исполнимом файле эмуляторе. Таковой прием подразумевает полную подмену перехваченной функции. Работы с ПЗУ не происходит вообщем. Эмулятор также перехватывает системные функции, чтоб генерировать действия «Гремлинов» в ОС. К примеру, System Manager употребляет функцию SysEvGroupWait когда в ОС не происходит событий, которые могли бы заинтриговать прикладную програмку. Обычно, SysEvGroupWait перекрывает текущий поток, предоставляя возможность работать иным потокам либо переключая Palm в «сон» до первого действия, для которого машина обязана «проснуться».
При работе «Гремлина», PalmOS Emulator перехватывает SysEvGroupWait и отправляет действия. Потом SysEvGroupWait работает как традиционно. Так как в очереди событий возникает событие, которое мы лишь что вставили, SysEvGroupWait немедля завершается, позволяя передать его прикладной програмке. Эти примеры подразумевают перехват функций «с головы», вставку процедур обработки до того, как функция ПЗУ завершится (ежели ПЗУ она вообщем запускается). Но есть случаи, когда необходимо перехватить управление опосля того, как функция отработает. Перехватывая функцию «с хвоста» мы прерываем позже выполнения опосля того, как предпочитаемая системная функция завершится. Нужен несколько наиболее продвинутый метод, так как при таком подходе нет точного признака, что системные функции завершились. Когда системная функция вызывается, то мы лицезреем аннотацию TRAP $F, которую просто отыскать и перехватить. Когда системная функция передает управление програмке, которая инициировала как пуск, она просто выполняет аннотацию RTS, которая ничем не выделяется посреди остальных случаев ее использования. Чтоб перехватить функции опосля того, как системная функция завершится, RTS просит маленький доработки. Предварительно мы перехватываем аннотацию TRAP $F, которая значит обращение к системным функциям. Потом, заместо эмуляции аннотации TRAP $F, значение регистра счетчика команд заносится в стек (что значит, перехват управления при работе аннотации RTS), PalmOS Emulator сохраняет значение регистра PC в таблице и заносит указатель на аннотацию TRAP $E в стек. Эта системная функция преобразуется в исправленный «хвост». Когда системная функция доходит до аннотации RTS, регистр PC указывает на аннотацию TRAP $E. Мы уже знаем способ перехвата аннотации TRAP, это просто и PalmOS Emulator перехватывает управление просто и проч. В обработчике аннотации TRAP $E PalmOS Emulator изменяет значение регистра PC, занося в него указатель из ранее приготовленной таблицы, потом выполняет любые нужные при перехвате деяния. Таковой способ употребляется для перехвата EvtGetEvent, когда записывается извлеченные действия, когда употребляется режим записи действия в журнальчик.
Вызов системных функций
Прерывание системных функций — лишь половина общей картины очень занятных отношений PalmOS и PalmOS Emulator. Благодаря перехвату мы можем передавать управление от эмулируемого ПЗУ PalmOS в двоичный код PalmOS Emulator. Чтоб картина была завершенной, нужен способ, который дозволял бы PalmOS Emulator запускать функции PalmOS. Способ, который был использован в PalmOS Emulator — это несколько переработанная прием, придуманный Грегом для CoPilot. Мысль в том, чтоб прекращать цикл работы эмулятора инструкций ЦП в некой комфортной и безопасной позиции (Грет прерывал процесс эмуляции на инструкциях TRAP $F), сохраняем состояние регистров ЦП, заносим нужные характеристики в стек и потом задаем аннотацию TRAP $F с номером подходящей системной функции. Потом, управление опять передается в основную функцию точно так же, как это происходит в случае перехвата «хвоста» подпрограммы: мы храним обратный адресок аннотации TRAP (в данном случае, аннотации TRAP $D) на стеке перед вызовом системной функции. Когда системная функция передает управление вызывающей програмке, запускается аннотация TRAP $D, PalmOS Emulator перехватывает эту ситуацию и наводит порядок, записывая в регистры ЦП те значения, которые были там до вызова системной функции. При таком способе, мы можем запускать системные функции, не мешая обычной работе PalmOS.
PalmOS Emulator употребляет этот прием повсевременно. К примеру, как уже говорилось, программы инсталлируются из файлов .PRC при помощи сотворения базы данных из файла PRC. Это проделывается вызовом в эмуляторе подпрограммы PalmOS DmCreateDatabase и DmNewResource.
История длится
В данной статье, я обсудил история PalmOS Emulator, от первых разработок Грега Хьюджгилла, Бернрда Шмидта и Крейга Шеффилда и главные принципы, на базе которых он был реализован. Вы также узрели, как PalmOS Emulator развивается. PalmOS Emulator в текущее время находится в процессе развития. Я предполагаю, что в течение наиблежайшего года будут появляться новейшие редакции программы, в каких покажутся новейшие функции и реализуется возможность эмуляции новейших моделей ручных ПК на базе PalmOS. Ежели вы желаете принять роль в развитии PalmOS Emulator, то сможете подписаться на перечень рассылки на ls.palm.com и просмотреть информацию по нескольким ссылкам:
Веб-сайт Palm Computing, созданный для разрабов: www.palm.com/developers/
Перечень рассылки Palm Computing: ls.palm.com
Web-узел Грега Хьюгила: www.hewgill.com
Web-узел Illume Software: members.aol.com/illumesoft/illume.html
Web-узел UAE: www.freiburg.linux.de/~uae
Руководящие принципы для разрабов
Мариц Шарп, менеджер по техническому сопровождению разрабов Palm Computing, поделился с нами некими принципами, которые может применять создатели ПО для PalmOS. Эти приемы предоставляют для вас способ для сотворения надежных и совместимых с будущими версиями PalmOS программ.
Один способ разработки надежных программ — разработка защищенного кода, в который добавляется множество вызовов ErrNonFatal-DisplayIf, которые в процессе отладки разрешают проверить ваши догадки о том, как работает программа. Много заморочек можно изловить таковым образом, эти доп вызовы не замедляют вашу програмку. Вы сможете сохранить более принципиальные проверки в коммерческой версии, используя подпрограмму ErrFatalDisplayIf. И можно проверить несколько остальных возможных заморочек:
Считывание и запись в память по нулевому указателю либо в область нижней памяти; не запамятовывайте инспектировать итог функций MemSet, MemMove и проч., чтобы убедиться, что употребляются корректные указатели (ежели вы сможете воплотить наиболее полную проверку — это даже лучше). Не считая тог, можно проверить, что указатели на ваши структуры данных либо передаваемые функциям PalmOS также не NULL. В отладочной версии будет уместно перекрыть вызовы MemMove (и схожих) при помощи директивы препроцессора #define для проверки правильности характеристик.
Распределение объектов нулевой длины: это некорректно, нельзя задавать объекты с нулевой длиной либо поменять длину буфера до NULL. PalmOS 2.0 и прошлые редакции допускали это, но будущие редакции ОС могут не позволять таковых приемов.
Догадки о мониторе: начало видеопамяти, размер и количество пикселов на бит не заданы надолго; они могут поменяться. Не перехватывайте функции работы с окнами и графикой. Ежели вы собираетесь работать с аппаратными средствами без ОС, обходя API, сохраните состояние и верните ОС в первоначальное состояние в конце программы.
Доступ к глобальным переменным и программирование аппаратных средств: адреса глобальных переменных могут поменяется, используйте документированные функции API либо прекратите работу вашей программы, ежели версия ОС. которую вы определили, не соответствует той, в какой вы тестировали ее. Не считая того, будущие модели могут работать на ином ЦП.
Не переполняйте стек: создавая множество локальных переменных либо одну, но огромную, вы сможете столкнуться с очень сложной для отладки ошибкой, связанными с повреждением динамической памяти. Наибольшая емкость стека — 2 Кбайт, как можно реже используйте переменные, которые заносятся в стек.
Встроенные программы могут поменяться: формат и размер «предпочтений» (и данных) и проч. Ежели вы используете познание о структуре данных обычных программ, то советуем перекрыть работу программы при запуске в среде неправильной версии PalmOS.
Мы объединили достоинства Palm Simulator и CoPilot, разработав просто убойный инструмент для PalmOS-разработчиков, который не зависит от той платформы, на которой основаны их ПК. По материалам handy.ru
Смотрите также:
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
ЭЭХ! Оптимизированный портал для КПК (PDA), всё о карманных компах, для карманных компов, КПК, PDA
Ввысь!
К списку разделов
Среди наших партнеров:
|