программирование geek OSDev операционная система ассемблер разработка длиннопост 

ОСдев №10: основной загрузчик, часть 3. GDT.

Подготовительный этап закончен, можно приступать к интересному. Кроме собственно загрузки файлов наша программа должна подготовить для ОС рабочую среду. Это значит: переключить процессор в 32/64-битный режим, настроить таблицу прерываний и создать базовую GDT. Сегодня разберёмся с последним пунктом.

GDT - сокращение от Global Descriptor Table, глобальной таблицы дескрипторов. Что это такое? По сути - набор записей одинакового формата, описывающих области памяти и разрешения, которые они имеют. Упрощённо это выглядит так:

//область 0

адрес области

размер области

параметры доступа

флаги

//область 1

адрес области

размер области

параметры доступа

флаги

...

В 32/64-битном режиме дескрипторные таблицы используются вместо старой схемы адресации сегмент:смещение. Зачем? Сегмент:смещение - небезопасная технология, которая позволяет переписать любой участок памяти. Надо ли говорить, что при неосторожном обращении это легко может закончиться бедой? Дескрипторная таблица даёт возможность ограничить запись или выполнение кода в отдельных областях RAM. Дескрипторные таблицы появились как часть аппаратной защиты памяти вместе с 286 процессором.

Как это работает? После выхода из 16-битного режима процессор больше не принимает адреса в формате сегмент:смещение. Если попытаетесь так сделать - получите исключение GPT (General Protection Fault). Вместо этого в сегментном регистре процессор ожидает получить смещение дескриптора внутри ДТ. При этом для операций над этим сегментом будут действовать правила, указанные в дескрипторе. Например, попытка обратиться к памяти за пределами сегмента или запись в защищённый от записи сегмент будут вызывать исключения (кстати, про обработку исключений поговорим позже, пока давайте примем, что это фатальная ошибка, которая приведёт к остановке программы).

Кроме глобальной таблицы дескрипторов существуют ещё локальные (ЛДТ), TSS и таблицы дескрипторов прерываний (IDT). Для того, чтобы наша ОС могла начать работу, обязательно наличие только двух таблиц: GDT и IDT. Давайте теперь взглянем на GDT поподробнее. Скажу сразу, зрелище будет не очень приятное. Но начнём с лёгкого. Так как GDT - часть аппаратной схемы защиты памяти, у неё есть свой регистр: GDTR. Это 48-битный регистр, 4 байта которого предназначены для смещения GDT, а 2 - для её размера. Таким образом, GDT не может быть больше 65536 байтов в размере. Размер записи в GDT - 8 байтов, значит,< таблица может иметь максимум 8192 дескриптора. Зная всё это, хорошим тоном было бы сразу зарезервировать 64К под GDT, но в моей архитектуре ОС создаёт свои таблицы, так что сейчас я обойдусь минимумом. Минимум в данном случае - 3 дескриптора. Нулевой, сегмент кода и сегмент данных. Зачем отдельно выделять нулевой дескриптор? Дело в том, что обращение к нему в GDT приводит к, вы угадали, исключению. Это тоже своего рода мера предосторожности.

А теперь время взглянуть на структуру дескриптора. И тут, увы, наследие тяжёлого прошлого во всей красе. Ради обратной совместимости в кодом для старых процессоров дескриптор GDT превратили в кашу.

Первые два байта - это первые 16 битов границы сегмента.

Следующие три байта - первые 24 бита основания сегмента.

Следующий байт - параметры доступа. Рассмотрим ниже.

Следующий байт совмещает в себе биты 16-19 границы и флаги. Об этом тоже подробнее ниже.

Ну и последний байт - биты 24-31 основания.

Неудобно? Не то слово. Когда будем писать ядро - обязательно замутим процедуру для комфортной работы с этим месивом. К счастью, сейчас у нас статичная структура всего из трёх сегментов, так что заполнить можно и вручную. Создадим и подключим модуль GDT.inc. Как это сделать, мы рассматривали в прошлый раз. И добавим в него вот такую таблицу:

;Нулевой дескриптор, сЫ 00001л бы 00001л db 001л
с1Ь 00000000Ь с1Ь 00000000Ь с!Ь 001л
¿Дескриптор сегмента бы 0РРРР1л с!ы 00001л с!Ь 001л
дЬ 10011010Ь с!Ь 11001111Ь с!Ь 001л
¿Дескриптор сегмента бы 0РРРР1л бы 00001л с!Ь 001л
6Ь 10010010Ь 6Ь 11001111Ь с1Ь 001л
¿Биты 0-15 предела.
¿Биты 0-15


Это и есть наша GDT, ничего ужасного. Значения в нулевом дескрипторе для нас не важны, а вот остальные давайте рассмотрим подробнее. У нас есть два дескриптора: один - для кода, другой - для данных. Оба начинаются с 0 и занимают FFFFF*4Kib = 4Gib. Фактически это значит, что, начав работать, ОС сможет использовать всю память по своему усмотрению. Давайте теперь разберём параметры доступа и флаги.

Бит 1 - флаг чтения/записи. Его значение различается для сегментов кода и данных.
Для сегментов кода установленный флаг означает, что чтение разрешено.
Запись в сегменты кода запрещена всегда.
Для сегментов данных установленный флаг означает, что разрешена запись. Чтение из сегментов данных

Таким образом, значение параметров доступа 10010010b даёт нам вот что: это сегмент данных, запись в него разрешена, сегмент растёт вверх, уровень привилегий - ring0. А теперь флаги. Биты 0-3 здесь заняты границей сегмента, не обращаем на них внимания.

Бит 4 зарезервирован и должен быть равен 0.
Бит 5 указывает на 64-битный сегмент. Так как мы пока переходим в 32-битный, должен быть равен 0.
Бит 6 указывает на 32-битный сегмент. Наш выбор, устанавливаем в 1.
Бит 7 - гранулярность. Если равен 0, то значение границы сегмента используется как

Окей, теперь у нас есть GDT. Но как указать системе, что её нужно использовать? Процессор ведь не дурак, сам искать не станет. Всё просто, джентльмены из IBM в кои-то веки о нас позаботились. При помощи специальной ассемблерной команды lgdt (load GDT) мы можем передать в регистр GDTR линейный адрес таблицы и её размер. Для этого добавим перед GDT такую структуру:

60ТК_р1:г:
dы 00171п	;Размер таблицы - 1 (23 байта).
dd 00000000И	;Абсолютный адрес таблицы.,программирование,geek,Прикольные гаджеты. Научный, инженерный и  айтишный юмор,OSDev,операционная система,ассемблер,разработка,длиннопост

Размер таблицы мы уже знаем, а вот адрес придётся посчитать, так что пока оставим 0 и напишем процедуру инициализации GDT:

init_GDT ргос
init_GDT endp
push eax pushfd
xor eax,eax
mov ax,offset GDT
add eax,00000500h
mov dword ptr [GDTR_ptr+2],eax
cli
lgdt pword ptr GDTR_ptr sti
popfd pop eax ret,программирование,geek,Прикольные гаджеты. Научный, инженерный и  айтишный юмор,OSDev,операционная

На случай, если тут не всё очевидно, поясню. Мы помещаем в EAX смещение GDT относительно сегмента, а потом добавляем адрес сегмента*16. Это и есть линейный адрес, сохраняем его в структуре. После этого отключаем прерывания, передаём структуру процессору командой lgdt и включаем прерывания обратно. По идее прерывания можно не трогать, так как в 16-битном режиме GDT не используется, но я перестраховщик.

Собственно, на этом всё. Добавьте вызов init_GDT в конец загрузчика перед cli и дело в шляпе. Сегодня без картинки, но вот вам котик.

программирование,geek,Прикольные гаджеты. Научный, инженерный и  айтишный юмор,OSDev,операционная система,ассемблер,разработка,длиннопост

Чистая дискета: https://drive.google.com/file/d/1Bold4ds8oEruHQ7fJZKHglVo7A2Vc5MR/view?
Предыдущие части:
Развернуть

старые игры Atari 2600 

История видеоигр, часть 33: Indy 500 (1977)

game program'" INDV 500 Use with Driving Controllers,старые игры,Atari 2600

Недавно я писал про Street Racer, которая, как и Indy 500, была одной из стартовых игр для Atari 2600. В конце статьи я сделал игре скидку из-за новизны системы и отсутствия у автора опыта работы с ней. Это было до того, как я увидел Indy 500. Теперь я беру свои слова обратно -- на Atari 2600 уже тогда можно было реализовать динамичную и графически привлекательную гоночную игру, просто приняв правильные дизайнерские решения.

старые игры,Atari 2600

Ларри Каплан жаловался, что не смог сделать плавный скроллинг трассы в Street Racer -- в Indy 500 вся трасса умещается на одном экране и скроллинг не нужен.

В Street Racer нет ощущения скорости -- в Indy 500 машина ускоряется, тормозит и дрифтует так, что через несколько минут игры начинаешь чувствовать её массу и инерцию.

В Street Racer машина управляется как пушка из Space Invaders -- Indy 500 поддерживает аналоговый контроллер и плавное вращение спрайтов.

старые игры,Atari 2600

В Indy 500 почти в два раза меньше вариантов игры, чем в Street Racer, но это тот случай, когда качество победило количество.

старые игры,Atari 2600

Эта трасса называется Devil's Elbow, Локоть Дьявола.
Я не смог проехать ни одного круга без десятка-другого
вылетов на обочину.

Эд Риддл при создании игры вдохновлялся гоночным событием под названием Indianapolis 500, знакомому многим любителям заездов на скорость. В отличие от прототипа, Indy 500 не ограничивается нарезанием кругов наперегонки. Кроме традиционных гонок тут  есть состязание по сбиванию призовых коробок, "автосалочки" и гонки на льду со "скользкой" физикой.

старые игры,Atari 2600

Здесь моя задача -- протаранить как можно больше голубых коробок,
пока не истекло время. Каждый раз, когда я наезжаю на цель, мне
засчитывается очко, а цель появляется в другом месте.

В каждую из представленных игр можно сыграть как с другом, так и одному, наперегонки с таймером. Единственная обязательно парная игра -- салочки, но и тут соперника может заменить компьютер.

старые игры,Atari 2600

Моя машина (жёлтая) сейчас мигает, поэтому её не видно на скриншоте.
Это значит, что я должен убегать, а игрок в синей машине -- пытаться
меня догнать.

старые игры,Atari 2600

Эта ледяная трасса выглядит проще остальных, но на деле игроку,
не освоившему управляемых заносов, здесь придётся туго.

Indy 500 можно со спокойной совестью рекомендовать всем любителям ретрогейминга. Она не пытается прыгнуть выше головы и не ломает представления о возможностях системы. Это просто качественная и разнообразная для своего времени игра. И в отличие от Street Racer, где было всё что угодно кроме стритрейсинга, Indy 500 -- действительно про гонку Индианаполис 500.

Оригинал: https://silicondarwin.blogspot.com/2017/06/indy-500-1977.html

Развернуть

старые игры Atari 2600 

История видеоигр, часть 32: Air-Sea Battle (1977)

ata ni 7600 VIDEO GAME ATARI aVW cartridge ÄIR-SEA BATTLE,старые игры,Atari 2600

Могу себе представить радость маленького милитариста из семидесятых, когда родители вручали ему картридж с Air-Sea Battle для новенькой Атари VCS. Бомбардировщики, зенитки, истребители, вертолёты, дирижабли, линкоры и картонные уточки из тира -- всё это умещалось в одной маленькой коробочке, рассортированное на 27 игр.

старые игры,Atari 2600

Которые, в свою очередь, были организованы в шесть тематических групп. В первой игрок или игроки отстреливали воздушные цели из стационарных орудий. Во второй -- управляли подвижными субмаринами, которые атаковали торпедами проплывающие корабли. Как обычно в случае с ранними аркадами, единственная цель в любом варианте Air-Sea Battle -- набрать счёт больше, чем у соперника.

старые игры,Atari 2600

Дирижабли (или воздушные шары) с литерой А стоят 0 очков и
только мешают стрельбе.

Далее по списку игрокам представлялась возможность поуправлять ружьём в тире, кораблём и бомбардировщиком. Некоторые поздние вариации игры были устроены в виде дуэли, где игрокам приходилось выбивать очки друг из друга.

старые игры,Atari 2600

Тир. Кролики, уточки и клоунские рожицы.

Журнал Video назвал Air-Sea Battle ультимативной игрой для любителей взрывать всё подряд, прочая игровая пресса тоже не скупилась на оценки. Конечно, старушке не тягаться с играми на современных платформах, но держится она достаточно бодро. И бонусный факт: Air-Sea Battle была первой игрой от Ларри Каплана, одного из сооснователей Activision.

Оригинал: https://silicondarwin.blogspot.com/2017/06/air-sea-battle-1977.html

Развернуть

старые игры Atari 2600 гонки 

История видеоигр, часть 31: Street Racer (1977)

k Warne* Communicaiions Company
STREET RACER
GAME PROGRAM "
winery STREET RACER '-SLALOM-y #DODGEM'-JET SHOOTER •
# GAM E5 NUMBER CRUNCHER™ • SCOOP BALL™,старые игры,Atari 2600,гонки


Чего бы вы ждали от игры с названием Street Racer? Тюнингованных тачек с хромированными дисками? Адреналиновых заездов по брызжущим неоном ночным улицам? Лихих заносов и воя полицейских сирен за спиной? А вот вам:

старые игры,Atari 2600,гонки

Street Racer - одна из девяти стартовых игр для Atari 2600 (в девичестве Atari VCS). Как удручённо признал сам автор, Ларри Каплан, программа слабо использовала возможности системы. Так, например, он не смог реализовать эффект уплывающей назад трассы, благодаря чему Street Racer -- единственная в мире гоночная игра с нулевым ощущением динамики. Спрайты машин и препятствий тоже не претендуют, даже по меркам Atari 2600. Зато, как это часто бывало на Atari 2600, Street Racer -- это целый набор игр с немного различающимися правилами и сложностью, всего 27 штук. Все их можно разделить на шесть больших групп.

Street Racer

Титульная игра, в которой вам надо уклоняться от вылетающих навстречу соперников. Похожи ли машинки на скриншоте на автомобили, которые можно встретить на улицах города? Чёрта с два. Скорее это формульные болиды. Но при чём тогда здесь стритрейсинг?

старые игры,Atari 2600,гонки


Slalom

Вместо гоночной трассы теперь (предположительно) горный склон, перегороженный стенами с узкими воротами, в которые вам предстоит ужом проскальзывать.

013101310131013101310131013101310131013101310131013101000131,старые игры,Atari 2600,гонки


Dodgem

Дурацкая вариация, в которой машина игрока не фиксирована в нижней части поля, а раз за разом проезжает весь экран снизу вверх, уворачиваясь от некоего ромбовидного объекта.

старые игры,Atari 2600,гонки


Jet Shooter

Смехотворная пародия на шутер, где игрок управляет самолётом и отстреливает летящих ему навстречу врагов. Несостоятельным в геймплейном смысле его делает то, что игрок может выпустить только один снаряд, и если тот прошёл мимо, то придётся ждать, пока он не скроется за горизонтом. А летит он, поверьте, медленно.

старые игры,Atari 2600,гонки


Number Cruncher

Странным образом, этот вариант оказался довольно приятным. Вместо того, чтобы уворачиваться от чего-то, здесь игроку нужно ловить летящие на него цифры, зарабатывая очки. Ловить, впрочем, надо аккуратно -- сталкиваться с цифрами можно только фронтально, иначе -- ДТП.

старые игры,Atari 2600,гонки


Scoop Ball

Scoop Ball сажает игрока за руль чего-то типа скоростного бульдозера, снабжённого ковшом, которым нужно подбирать на трассе знаки "+", в то же время уворачиваясь от бульдозеристов-конкурентов.

старые игры,Atari 2600,гонки


В целом, учитывая молодость системы, тогда игра вышла не полной катастрофой. Но в наши дни удовольствия от неё вы не получите. Графика и звук -- чуть получше, чем в Miniature Golf, анимация спрайтов отсутствует, а главное -- это одна из очень немногих гоночных игр, во время которых можно уснуть от скуки. И она не имеет никакого отношения к стритрейсингу.

Развернуть

gamedev Игры Roguelike screenshotsaturday 

Beneath the Citadel v.0.18

Опоздал на целых три недели, прошу прощения. Рад бы сказать, что всё это время был активно занят разработкой и теперь выкачу вагон фич, но нет, виновники - работа и личная жизнь. Тем не менее, готова важная механика - события. Использована она пока не на полную катушку, но попробовать на зуб можно. Неуникальные события происходят на первом этаже с вероятностью 7% на комнату.

Кроме этого - пара новых монстров и видов оружия. Полный список изменений (на этот раз скромный) как всегда будет в комментах.

^te snapshot » a Reset suspeno Power-
i Ш M û ù Ф
Toadmen patrol
You see three toad like humanoids arguing about something in this room. They are armed with spears and wield light wicker shields. You remember their description from one of your lectures: they are waqiri, swamp-dwelling savages.

Куда двигаться дальше? Выбор возможных направлений всё ещё огромен: крафт, доработка магии, стелс, дополнительные боевые умения и перки, лор. Думаю, для следующей версии я сосредоточусь на свойствах предметов и дополнительных умениях игрока и существ. Это позволит сделать сразу большую пачку контента, который будет приятно пощупать.

^te snapshot » a Reset suspeno Power-
i Ш M û ù Ф
Husk
ft thin human figure shambles across the room. It is dressed in worn and dirty clothes and wears a common leather cap. Even in such dim illumination you can see that this is a husk - a dead and withered body animated by sorcery.
The figure

Ссыль на bochs:

https://drive.google.com/file/d/16k2Gpr7oPSekq4rAhmtBV0IPnIteDLlE/view?usp=sharing

Ссыль на дискету:

https://drive.google.com/file/d/1jI29Vk0VQYNz4ErQij3ztLEdSXKECkkZ/view?usp=sharing

^te snapshot » a Reset suspeno Power-
i Ш M û ù Ф
jagged sword
Crude sword with jagged blade and leather-wrapped grip. Type: weapon Durability: 32/32 Physical damage: 16
iq? Bochs for Windows - Display
CTRL + 3rd button enables mouse	IPS: 91,325M	A:	NUM	CAPS

Развернуть

старые игры atari 

История видеоигр, часть 30: Tank Trap (1977)

For the ATARI 400/800
An Exciting Graphic Animation Game By Don Ursem
QS
QUTJLny
SOFTW7IR6™,старые игры,atari

Случается, что витающая в воздухе идея попадает совсем не в ту голову. Так, игра, которую мог придумать только сходящий с ума от скуки рядовой российской армии, вдруг материализовалась в уме американца Дона Арсема. Судите сами: в самоволку ушёл танк (вероятно, с танкистами), и начальство поручает вам поймать мерзавцев, используя только списанные кирпичи и цемент.

TANK	TRAP
BY OOM	URSEM
CCJ 1980 Quality Software
DIFFICULTY LEVEL
1,старые игры,atari

Процесс ловли подарит вам пару часов весёлого времяпрепровождения. Выглядит так: по одноэкранному игровому полю беспорядочно носится танк; игрок контролирует человечка, который, хотя и бегает медленнее танка, зато оставляет за собой бетонную стену. Задача игрока - запереть танк в небольшом замкнутом пространстве. Потыкавшись в стены и не найдя выхода, тот рано или поздно сдастся. Игрок терпит поражение, если его давит танк.

старые игры,atari

Победа, танк заперт в левом верхнем квадрате. На скриншоте его не видно, потому что
танк перестаёт отображаться после вывода сообщения.

На самом деле условие победы звучит так: "столкнувшись со стеной, танк сделает девять случайных разворотов; если при этом он не найдёт выхода, то сдастся". Это значит, что теоретически не обязательно окружать танк стеной. Достаточно нескольких блоков и везения. Кстати, построенный мной в этой партии квадрат - не оптимальное решение. Кривые стены с выступами и нишами поставят танк в тупик гораздо быстрее.

старые игры,atari

У левой границы экрана мы видим два танка. Сначала стирать, потом перерисовывать!

Игра имеет четыре уровня сложности. На первом поле обнесено стеной по периметру и танк не может выехать за пределы экрана. На втором ограждающей стены нет, и танк, выехав с одной стороны поля, появляется с противоположной. Кроме того, часть оставленных игроком блоков состоит из долго застывающего бетона, который танк может протаранить. Впрочем, есть вероятность, что при ударе бетон затвердеет и задержит танк.

старые игры,atari

Синие участки стены - ненадёжные. Если танк натолкнётся на них, то
они или превратятся в нормальные или исчезнут.

На третьем уровне на поле появляются гражданские. Их, по идее, надо защищать, но, как я ни старался узнать, что будет, если танк переедет одного из них, ничего не вышло; водитель машины наотрез отказывался давить людей. Насколько я понимаю, гибель гражданского - не конец игры, но очков с финального счёта спишут.

старые игры,atari

На четвёртом уровне танк иногда стреляет из пушки и ломает построенные игроком стены, но только если игрок отдаляется от танка на четыре или более клетки.

старые игры,atari

Tank Trap не может похвастаться детальной графикой, но звуковое сопровождение не раздражает, а коротенькие мелодии, звучащие в начале и конце раунда, вполне приятны на слух. Управлению несколько недостаёт чувствительности. Часто игрок гибнет под гусеницами танка просто потому что персонаж не отреагировал на нажатие кнопки направления.

YOU TRAPPED THE TANK IN 285 MOOES AND USED ONLY 180 TRAPS.
FOR THIS, YOU'VE EARNED..
THE RANK OF
★ ★ ★ ★
FULL GENERAL,старые игры,atari

По окончании партии игрок получает звание в соответствии со своей
эффективностью.

Найти в интернете информацию об авторе у меня не вышло. Tank Trap была выпущена компанией SPD Software. Отсутствие у этой фирмы каких-либо других игровых проектов заставляет меня думать, что SPD Software -- и есть Дон Арсем, зарегистрировавшийся как компания для распространения Tank Trap. В 1981 году он ещё раз появится на сцене со Starbase Hyperion, после чего навсегда покинет игровую индустрию.

Развернуть

старые игры игровой автомат 

История видеоигр, часть 29: Space Wars (1977)

о ап

#
>-

os,старые игры,игровой автомат

Для тех, кто читает блог с самого начала, эта игра будет выглядеть знакомо. Да, действительно, перед нами клон Spacewar! 1962 года. Поиграв в оригинал, выпускник MIT Ларри Розенталь настолько впечатлился, что воспроизвёл игруна собственноручно собранном игровом автомате. Позже Розенталь каким-то образом заручился поддержкой компании Cinematronics для коммерческого выпуска Space Wars.

IS]
H
Ч 30
fio
п
*
-К
у,старые игры,игровой автомат

Как и Spacewar!, эта игра -- дуэль двух космических кораблей, управляемых игроками. События разворачиваются на одном экране, в центре которого находится звезда (впрочем, её можно отключить в настройках автомата), имеющая положительное или отрицательное гравитационное поле. Space Wars выглядит лучше предшественницы за счёт использования современного векторного дисплея. В последующие годы эта технология станет визитной карточкой Cinematronics.

14»
fi
a ai
fiG
П
1,старые игры,игровой автомат

Управление аналогично Spacewar!. Две кнопки отвечают за разворот вправо и влево, одна за ускорение, одна за стрельбу и одна за прыжок в гиперпространство. Боезапас игроков ограничен: на каждый раунд даётся 15 зарядов, которые можно выпустить в противника. Уход в гиперпространство телепортирует корабль игрока в случайную точку на экране. Это может стать спасением в чрезвычайной ситуации, но злоупотреблять таким манёвром не стоит: при каждом прыжке есть растущий риск сбоя и гибели корабля.

а а
G чг
ISO
IG
é^,старые игры,игровой автомат

Самое интересное нововведение -- возможность повредить корабль противника. В Spacewar! раунд заканчивался после первого же попадания, в Space Wars, если снаряд задел корабль по касательной, последний может лишиться нескольких деталей и потерять в скорости и манёвренности, но продолжить бой. Стоит, кстати, отметить красивый эффект разрушения кораблей на тучу векторных обломков, разлетающихся во все стороны. Ещё одно заметное новшество -- пролетающие время от времени по экрану астероиды.

Интересно, что, кинув в автомат четвертак, игроки покупали не отдельный раунд или несколько, а фиксированное время, в течение которого могли играть без ограничений.

Оригинал: https://silicondarwin.blogspot.com/2017/05/space-wars-1977.html

Развернуть

gamedev Игры Roguelike screenshotsaturday 

Beneath the Citadel v.0.18 (WIP)

Продолжаю пилить свой роуглайк. Главной фичей новой версии будут события. Что это такое? Если по-простому, - миниатюрные текстовые квесты, которые активируются при первом посещении комнаты игроком. Для меня это в первую очередь нарративный инструмент, потому что через них можно вводить элементы лора, которые иначе пришлось бы распихивать по случайным бумажкам, забытым дневникам и секретным документам, что на мой взгляд звенящая пошлость. Кроме того, это возможность разнообразить геймплейную рутину и задействовать те навыки и параметры персонажа, которые сейчас недостаточно нагружены.

^ Bochs for Windows - Display
Reset susPEno Rower-
Û *
ù ф
Dogs
You see a group of stray dogs tearing something on the floor apart. A moment later the dogs notice your presense and turn to you. Another moment and you realise that these are no ordinary stray dogs - their eye sockets are empty,

^te snapshot » a Reset suspeno Power-
i Ш M û ù Ф
Collapsing stonework
As you enter this room, several pieces of stonework fall from above. Evade (Dexterity)
iq? Bochs for Windows - Display
CTRL + 3rd button enables mouse IPS: 88,380M A: NUM CAPS SCRL,gamedev,Игры,Roguelike,screenshotsaturday

Развернуть

программирование geek OSDev операционная система разработка ассемблер длиннопост 

ОСдев №9: основной загрузчик, часть 2. Работа с дисплеем при помощи функций BIOS.

Дисклеймер: эта серия постов не про UEFI. Это не значит, что я не знаю о существовании UEFI. Про UEFI будет отдельная серия постов. Почему я не пишу про UEFI прямо сейчас? Потому что UEFI - это уровень абстракции над железом, а мне интересно именно железо и работа с ним.

Продолжаем? Сейчас наш загрузчик второго уровня работает в "немом" режиме - без возможности подать сигнал об ошибке или выполнении операции. Это необходимо исправить. Самое очевидное решение - вывод информации на дисплей. Мы уже условились, что на нынешнем этапе для работы нашей ОС будет необходима VGA-совместимая карта и дисплей, так что вправе рассчитывать на их наличие.

Программирование VGA-контроллера - сложная штука. Однажды мы ею обязательно займёмся, но сейчас, раз уж мы всё ещё в Реальном режиме, есть вариант попроще: функции BIOS. Функции, связанные с работой дисплея, доступны через прерывание 10h. Мы уже пользовались им для вывода текста в первичном загрузчике, но так как теперь мы не ограничены в размере программы, функционал можно будет расширить.

Первое, что нам стоит сделать - установить нужный видеорежим на случай, если BIOS этого не сделала. Кроме того, понадобятся функции считывания положения курсора, прокрутки экрана и вывода строки. Весь код, связанный с вводом/выводом будет храниться в отдельном файле. У меня он называется io.inc. Мы ещё не использовали подключаемые файлы, но ничего сложного тут нет: в TASM они объявляются директивой include, после которой идёт путь и имя файла. Единственная тонкость тут в том, что подключенный файл не будет вынесен в какую-то изолированную область памяти, как это делается в языках высокого уровня, а окажется в исполняемом файле именно там, где был объявлен. Поэтому лучше объявлять подключаемые файлы где-нибудь в конце, за пределами основного кода.

VGA имеет набор стандартных режимов отображения, с которым можно ознакомиться тут:

http://www.columbia.edu/~em36/wpdos/videomodes.txt

Нас интересует режим номер 3 - 80х25 символов, 16 цветов. Для его включения создадим в файле io.inc процедуру set_vmode3. Её полный текст будет выглядеть так:

set_vmode3 proc
                                  push ax
                                  push bx
                                  pushf


                                  xor ax,ax
                                  mov ah,0Fh
                                  int 10h
                                  cmp al,03h
                                  je @@exit_good


                                  mov ax,0003h
                                  int 10h


                                  xor ax,ax
                                  mov ah,0Fh
                                  int 10h
                                  cmp al,03h
                                  jne @@exit_bad


@@exit_good:          mov byte ptr vmode,al
                                  mov byte ptr vcol,ah
                                  mov byte ptr vrow,19h
                                  mov byte ptr vpage,bh


                                  popf
                                  clc
                                  pop bx


                                  pop ax
                                  ret


@@exit_bad:            popf
                                  stc
                                  pop bx
                                  pop ax
                                  ret
set_vmode3 endp

Начинается процедура, как и почти всегда у меня, с сохранения состояния используемых регистров в стеке. Это нетипичный для ассемблера подход. Обычно, создавая низкоуровневый код, программист стремиться максимально оптимизировать использование инструкций, по возможности обходясь без обращений к памяти, использования стека и вызова процедур. К сожалению, при работе над большим проектом это невозможно, и я на горьком опыте выяснил, что лучше потратить лишние циклы на инкапсуляцию процедуры, чем потом мучительно отлавливать баг, который появился из-за того, что какой-то регистр внепланово изменил значение.

                    xor ax,ax                    mov ah,0Fh
                    int 10h
                    cmp al,03h
                    je @@exit_good

Этот блок нужен для того, чтобы остановить выполнение процедуры, если режим 3 уже установлен. Сначала регистр AX обнуляется, чтобы мы точно знали его значение. Функция 15 (0Fh) прерывания 10h возвращает в регистре AL номер установленного режима. Далее мы сравниваем результат с нужным значением (3), и если они равны, то переходим к завершению процедуры, метка @@exit_good. Если режим 3 не установлен, продолжаем.

                    mov ax,0003h                    int 10h

Здесь мы опять вызываем прерывание 10h со следующими параметрами: AH = 0(функция 0, установка видеорежима), AL = 3(номер режима). После этого снова идёт проверка режима. Если AL всё ещё не равен 0 - вероятно, возникла проблема, которую мы не сможем решить. Переходим к метке @@exit_bad. Если AL равен 3, продолжаем от @@exit_good. Первым делом - сохраняем в переменные параметры режима, которые вернуло прерывание 10h. В AL - номер режима; в AH - количество колонок символов; в BH - активную страницу видеопамяти (об этом позже). Параметр vrow не возвращается, потому что технически количество символьных строк ограничено только объёмом видеопамяти, а не размером дисплея. После этого восстанавливаем сохранённые в начале регистры, устанавливаем CF (флаг переноса) в нужное положение и завершаем процедуру.

Готово. Теперь в основной модуль после call read_BPB добавляем call set_vmode3 и после этого jc panic. JC - инструкция условного перехода. Переход выполняется при установленном флаге CF. То есть, если наша процедура set_vmode3 завершилась неудачно, программа продолжится от метки panic. Так как невозможность установить видеорежим говорит либо о серьёзных неполадках, либо о несовместимом оборудовании, продолжать выполнение смысла нет. После метки panic останавливаем программу инструкциями cli и hlt.

Далее стоит вывести какое-нибудь приветствие или заголовок, просто чтобы уведомить пользователя о том, что программа работает. Для этого первым делом стоит узнать положение курсора, ведь на экране скорее всего уже есть какой-то текст от BIOS. Это тоже можно сделать с помощью прерывания 10h. Добавьте в io.inc процедуру get_cursor_pos:

get_cursor_pos proc                                      push ax
                                      push bx
                                      push cx
                                      push dx
                                      pushf


                                      mov ah,03h
                                      mov bh,byte ptr vpage
                                      int 10h
                                      mov byte ptr cursor_X,dl
                                      mov byte ptr cursor_Y,dh


                                      popf
                                      pop dx
                                      pop cx
                                      pop bx
                                      pop ax
                                      ret
get_cursor_pos endp

Про сохранение/восстановление используемых регистров объяснять больше не буду, а в остальном тут всё просто: вызываем функцию 3 прерывания 10h, в BH передаём активную страницу видеопамяти. Прерывание возвращает в DL позицию курсора по X, а в DH - по Y. Сохраняем в переменных. Готово. Далее нам понадобится процедура для прокрутки содержимого дисплея. Тут чуть сложнее, добавьте в io.inc:

scroll_up proc                                     push ax
                                     push bx
                                     push cx
                                     push dx
                                     pushf


                                     mov ah,06h
                                     mov bh,CS_DEFAULT
                                     xor cx,cx
                                     mov dl,byte ptr vcol
                                     dec dl
                                     mov dh,byte ptr vrow
                                     dec dh
                                     int 10h


                                     popf
                                     pop dx
                                     pop cx
                                     pop bx
                                     pop ax
                                     ret
scroll_up endp

Функция прокрутки экрана BIOS требует, во-первых, цветовую схему, которой будут заполнены очищенные строки, а во-вторых, координаты верхнего левого и правого нижнего углов сдвигаемой области. Цветовая схема передаётся в регистре BH и состоит из цвета фона и цвета символа. Мы ещё не объявляли константы, давайте посмотрим, как это делается. Константы в отличие от подключаемых файлов можно объявлять где угодно, так как они нужны только на этапе компиляции и не попадают в исполняемый файл. В TASM для объявления констант используется инструкция equ. Вся конструкция выглядит так: ИМЯ КОНСТАНТЫ equ ЗНАЧЕНИЕ КОНСТАНТЫ. Так как в стандартной палитре третьего режима всего 16 цветов, уместно будет определить их в виде констант. Добавьте в код такую запись:

;Цвета фона.BC_BLACK               equ byte ptr 00h
BC_BLUE                 equ byte ptr 10h
BC_GREEN              equ byte ptr 20h
BC_CYAN                 equ byte ptr 30h
BC_RED                   equ byte ptr 40h
BC_MAGENTA          equ byte ptr 50h
BC_BROWN             equ byte ptr 60h
BC_LIGHTGRAY      equ byte ptr 70h


;Цвета символа.
SC_BLACK               equ byte ptr 00h
SC_BLUE                 equ byte ptr 01h
SC_GREEN              equ byte ptr 02h
SC_CYAN                 equ byte ptr 03h
SC_RED                   equ byte ptr 04h
SC_MAGENTA         equ byte ptr 05h
SC_BROWN             equ byte ptr 06h
SC_LIGHTGRAY      equ byte ptr 07h
SC_DARKGRAY       equ byte ptr 08h
SC_LIGHTBLUE       equ byte ptr 09h
SC_LIGHTGREEN   equ byte ptr 0Ah
SC_LIGHTCYAN      equ byte ptr 0Bh
SC_LIGHTRED        equ byte ptr 0Ch
SC_LIGHTMAGENTA equ byte ptr 0Dh
SC_LIGHTBROWN  equ byte ptr 0Eh
SC_WHITE               equ byte ptr 0Fh


;Несколько готовых цветовых схем.
CS_DEFAULT           equ BC_BLACK or SC_CYAN
CS_CLASSIC           equ BC_BLACK or SC_LIGHTGRAY
CS_DARK                 equ BC_BLACK or SC_DARKGRAY
CS_BLUE                 equ BC_BLUE or SC_LIGHTBLUE
CS_ALARM              equ BC_BLACK or SC_RED
CS_DEBUG              equ BC_BLUE or SC_WHITE
CS_INVERT             equ BC_LIGHTGRAY or SC_BLACK
CS_PANIC                equ BC_RED or SC_BLACK

Как видите, для передачи цвета фона/символа используется один байт. Нижние 4 бита отвечают за цвет символа, верхние - за цвет фона и некоторые другие эффекты (подчёркивание, мигание), которые нам сейчас не нужны. Теперь разберёмся с рабочей областью. Мы хотим сдвинуть вверх весь экран, поэтому верхняя левая точка будет в (0,0), а правая нижняя - в (число символов по X-1,число символов по Y-1). Первая передается в CX, вторая - в DX. Таким образом, код процедуры расшифровывается так:

AH=номер функции (6)BH=цветовая схема
CX=верхний левый угол рабочей области (0,0)
DX=правый нижний угол
Вызвать прерывание 10h

Процедура принимает число строк, на которое нужно прокрутить экран вверх, в AL. Добавьте после jc panic такой код:

                           call get_cursor_pos                           mov al,01h
                           call scroll_up

Последнее, что мы рассмотрим сегодня - вывод строки. Это функция 19 прерывания 10h. В качестве параметров она требует: сегмент и смещение строки в ES:BP; цветовую схему в BL; активную страницу видеопамяти в BH; позицию начала вывода по X в DL; позицию начала вывода по Y в DH; длину строки в CX; режим вывода в AL. Номер функции как всегда передаётся в AH.

Зная всё это, давайте подумаем, как организовать процедуру. В принципе тут всё почти однозначно, но что\ делать с длиной строки? Заносить в CX вручную перед каждым вызовом процедуры? Можно, но зачем раздувать код. Лучше включить эту информацию в саму строку. Например, приняв, что первые 16 бит строки будут содержать число символов в ней. У меня строка с заголовком загрузчика выглядит так:

str_title          dw 31                                                     ;Длина строки.                      db '=== Tardigrada Loader v.1.1 ==='    ;Строка.

Теперь давайте напишем саму процедуру в io.inc.

print_string proc                                   push ax
                                   push bx
                                   push cx
                                   push dx
                                   push bp
                                   push es
                                   pushf


                                   mov ax,0050h
                                   mov es,ax
                                   mov ax,1300h
                                   mov bh,byte ptr vpage
                                   mov cx,es:[bp]
                                   mov dh,byte ptr cursor_Y
                                   mov dl,byte ptr cursor_X
                                   add bp,0002h
                                   int 10h


                                   popf
                                   pop es
                                   pop bp
                                   pop dx
                                   pop cx
                                   pop bx
                                   pop ax
                                   ret
print_string endp

Наша процедура будет принимать два параметра: смещение строки в BP и цветовую схему в BL. Практически весь код - это заполнение регистров для вызова прерывания. В основном модуле после call scroll_up добавим:

                                   mov bl,CS_DEFAULT                                   mov bp,offset str_title
                                   call print_string
                                   mov al,01h
                                   call scroll_up

Этот код выведет заголовок и прокрутит экран ещё на одну строку вверх. Если всё сделано правильно, должно получиться что-то вроде этого:

^ Bochs for Windows - Display
USER ,__£
m2
■+Щ
•te
ТА
Reset susPEno Rower-
Û *
ujf'tnu vvwet
ù ф
Please visit :
. http://bochs.sourceforge.net . http ://www.nongnu.org/vgab ios
Bochs UBE Display Adapter enabled
Bochs 2.6.10.sun BIOS - build: 01/05/20
^Revision: 13752 $ $Date:

Чистая дискета: https://drive.google.com/file/d/1Bold4ds8oEruHQ7fJZKHglVo7A2Vc5MR/view?usp=sharing

Исходники: https://drive.google.com/file/d/144cHXVlBskSiKt9zTAR1V535UQCeUyBL/view?usp=sharing

Bochs: https://drive.google.com/file/d/16k2Gpr7oPSekq4rAhmtBV0IPnIteDLlE/view?usp=sharing

Развернуть

Игры старые игры atari 

История видеоигр, часть 28: Miniature Golf (1977)

MN ATURE GOLF
VIDEO COMPUTER SYSTEM ™
GAME PROGRAM
VIDEO
GAMES
MINIATURE GOLF ONE PLAYER*TWO PLAYERS,Игры,старые игры,atari

Если бы не название, в жизни бы не догадались, что перед вами симулятор минигольфа, а? Удивительный факт: игра Miniature Golf для Atari 2600 вышла до изобретения кругов. Никакого другого объяснения её графическому оформлению я не вижу. Даже самые ранние игры для этой приставки могли похвастаться более детализированной графикой.

Игры,старые игры,atari

На момент выхода игры Atari 2600 была ещё относительной новинкой, но всё-таки разработкой занималась сама Atari, а это значит, что отговорка "мы не знали, как работать с новой платформой", не годится.

Игры,старые игры,atari

Задача игрока -- допинать квадратный мяч до квадратной лунки за наименьшее число ударов. Как и в реальном минигольфе, поле тут извилистое и заставленное всевозможными препятствиями (прямоугольными). Загнав мяч в лунку, игрок переходит на следующее поле - всего их девять. Количество ударов ничем не ограничено, и проиграть в Miniature Golf невозможно, но для каждого этапа есть рекорд, к которому стоит стремиться.

Игры,старые игры,atari

Стоит рассказать про управление. Оно, конечно, незамысловато -- к замысловатому контроллеры Atari 2600 не располагают. На скриншоте вверху зелёная точка -- это мяч. Синий квадрат - клюшка, которой управляет игрок. Маленький синий прямоугольник -- лунка. Игрок может свободно перемещать клюшку по всему игровому полю. Рядом с мячом она движется медленно, чтобы облегчить прицеливание, а вдали -- быстро. По нажатию кнопки (единственной на контроллере Atari 2600) клюшка устремляется к мячу из той точки, где была установлена, и при ударе отправляет его в соответствующем направлении. При этом чем дальше клюшка была от мяча -- тем сильнее будет удар.

Игры,старые игры,atari

Оценивать графику в играх для Atari 2600 -- глупо. И всё-таки в Miniature Golf даже те скромные возможности, что были у системы, использованы только частично. Звуковое сопровождение, в принципе, соответствует - абстрактно и минималистично. Управление странное, но удобное -- когда привыкнешь.

Игры,старые игры,atari

Развернуть