Примечание: пришло несколько ответов. Подумайте об отмене ответов на новые вопросы.
- Common Lisp от happy5214
- Клиент из люцера
- Java от NeatMonster
- Javascript от Crempp
- C от Майка C
- C ++ от Дария Гоада
- Постскриптум от luser droog
- C ++ от JoeFish
- Javascript от полностью субъективный
- C от RichTX
- C ++ от Дэйва C
- Haskell от JB
- Питон от ja
8086 является первым x86 микропроцессор компании Intel. Ваша задача - написать для него эмулятор. Поскольку это относительно продвинутый уровень, я хочу ограничить его:
- Необходимо реализовать только следующие коды операций:
- мов, толчок, поп, хчг
- добавить, adc, sub, sbb, cmp и или или xor
- вкл, дек
- вызов, рет, JMP
- jb, jz, jbe, js, jnb, jnz, jnbe, jns
- stc, clc
- HLT, NOP
- В результате вам нужно только рассчитать флаги переноса, нуля и подписи
- Не используйте сегменты. Предположим
cs = ds = ss = 0
. - Нет префиксов
- Нет видов прерываний или порта ввода-вывода
- Нет строковых функций
- Нет двухбайтовых кодов операций (0F ..)
- Нет арифметики с плавающей точкой
- (очевидно) никаких 32-битных вещей, sse, mmx, ... того, что еще не было изобретено в 1979 году
- Вам не нужно считать циклы или делать какие-либо сроки
Начните с ip = 0
и sp = 100h
.
Входные данные: ваш эмулятор должен принимать двоичную программу в любом формате, который вам нравится, в качестве входных данных (чтение из файла, предопределенный массив, ...) и загружать его в память по адресу 0.
Вывод: видеопамять начинается с адреса 8000h, каждый байт - один (ASCII-) символ. Эмулируйте экран 80x25 на консоль. Обрабатывайте нулевые байты как пробелы.
Пример:
08000 2E 2E 2E 2E 2E 2E 2E 2E 2E 00 00 00 00 00 00 00 ................
08010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
08020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
08030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
08040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
08050 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 00 00 00 Hello,.world!...
Примечание: это очень похоже на реальный режим видео, который обычно составляет 0xB8000 и имеет еще один байт на символ для цветов.
Критерии победы:
- Все перечисленные инструкции должны быть выполнены
Я сделал тестовую программу без комментариев ( ссылка , источник nasm ), которая должна работать правильно. Выводит
......... Hello, world! 0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ################################################################################ ## ## ## 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 ## ## ## ## 0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 ## ## ## ## 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ################################################################################
Я не совсем уверен, должен ли это быть Codegolf; Это довольно сложная задача, поэтому любая заявка все равно выиграет много голосов. Прокомментируйте, пожалуйста.
Вот несколько ссылок, которые помогут вам в этой задаче:
- формат инструкции , больше
- таблица кодов операций
- описания кода операции
- 16-битное модовое R / M байтовое декодирование
- регистры , флаги регистр
- 1979 Руководство
Это моя первая запись на этой платформе. Если есть какие-либо ошибки, пожалуйста, укажите на них; если я пропустил детали, просто спросите.
источник
Ответы:
Не стесняйтесь раскошелиться и сыграть в гольф: https://github.com/julienaubert/py8086
Я также включил интерактивный отладчик.
Существует три файла: emu8086.py (обязательно) console.py (необязательно для вывода на экран), disasm.py (необязательно, чтобы получить список asm в коде гольф).
Для запуска с дисплеем (примечание использует проклятия):
Для запуска с интерактивным отладчиком:
Для запуска с неинтерактивным «отладчиком»:
Программа « Codegolf » должна находиться в том же каталоге.
emu8086.py
console.py
disasm.py
На github
источник
Haskell,
256234196 строкУ меня была эта незавершенная работа в течение некоторого времени, я собирался немного отполировать ее перед публикацией, но теперь веселье официально началось, и больше не нужно его скрывать. При извлечении я заметил, что длина его ровно 256 строк, поэтому я полагаю, что это «замечательная» точка его существования.
Что в: едва хватает набора команд 8086, чтобы безошибочно выполнить бинарный пример. Самоизменяющийся код поддерживается. (prefetch: ноль байт).
По иронии судьбы первые достаточные итерации кода были длиннее и поддерживали меньше диапазона кода операции. Рефакторинг оказался полезным как для длины кода, так и для покрытия кода операции.
Что вышло: очевидно, сегменты, префиксы и многобайтовые коды операций, прерывания, порты ввода / вывода, строковые операции и FP. Изначально я следовал исходному
PUSH SP
поведению, но мне пришлось отказаться от него после нескольких итераций.Результаты флагов переноса, вероятно, очень запутаны в некоторых случаях
ADC
/SBB
.Во всяком случае, вот код:
Выходные данные для предоставленного образца двоичного файла полностью соответствуют спецификации. Попробуйте это с помощью вызова, такого как:
Большинство не реализованных операций просто приведет к сбою сопоставления с образцом.
Я все еще намерен немного больше учесть и реализовать реальный вывод с помощью проклятий.
Обновление 1: получено 234 строки. Лучше организовал код по функциональности, перестроил то, что могло быть, попытался придерживаться 80 столбцов. И рефакторинг АЛУ несколько раз.
Обновление 2: прошло пять лет, я рассчитывал обновить его, чтобы он мог безупречно скомпилировать последнюю версию GHC. По пути:
<$>
и<*>
в прелюдии.Как говорится в комментариях к коду, 5 строк (импорт Data.Char, отображения 8-битных регистров и дамп экрана) не соответствуют спецификациям, поэтому вы всегда можете сделать скидку на них, если почувствуете такую склонность :-)
источник
.|.
? / 10 чарC - 7143 строки (сам процессор 3162 строки)
РЕДАКТИРОВАТЬ: сборка Windows теперь имеет выпадающие меню для замены виртуальных дисков.
Я написал полноценный эмулятор ПК 80186 / V20 (с CGA / MCGA / VGA, звуковым бластером, adlib, мышью и т. Д.), Эмулировать 8086 любыми способами не так уж просто. Потребовалось много месяцев, чтобы стать полностью точным. Вот модуль процессора только из моего эмулятора.
http://sourceforge.net/p/fake86/code/ci/master/tree/src/fake86/cpu.c
Я буду первым, кто признает, что я использую слишком много глобальных переменных в этом эмуляторе. Я начал писать это, когда я был все еще довольно плохо знаком с C, и это видно. Мне нужно почистить это на днях. Большинство других исходных файлов в нем не выглядят так ужасно.
Вы можете увидеть весь код (и некоторые скриншоты, один из них ниже) здесь: http://sourceforge.net/p/fake86
Я был бы очень рад помочь кому-нибудь еще, кто хочет написать их самостоятельно, потому что это очень весело, и вы узнаете много о процессоре! Отказ от ответственности: я не добавил эмуляцию 8080 V20, так как она почти никогда не использовалась в программе для ПК. Похоже, много работы без выгоды.
источник
Постскриптум (
130200367517531222246 строк)Все еще в стадии разработки, ноЯ хотел показать некоторый код, чтобы побудить других показать какой-то код .Набор регистров представлен в виде одной строки, поэтому различные регистры размером в байты и слова могут естественным образом перекрываться, ссылаясь на подстроки. Подстроки используются как указатели повсюду, так что регистр и область памяти (подстрока строки памяти) могут обрабатываться в операторных функциях единообразно.
Затем есть несколько слов, чтобы получить и сохранить данные (байты или слова) из «указателя», из памяти, из mem [(IP)] (увеличение IP). Затем есть несколько функций для извлечения байта MOD-REG-R / M, установки переменных REG и R / M и MOD и их декодирования с использованием таблиц. Затем оператор функционирует, введя ключ в байт кода операции. Так что цикл выполнения прост
fetchb load exec
.Я реализовал лишь несколько операционных кодов, ноПолучение расшифровки операнда стало для меня такой вехой, что я хотел поделиться им.редактировать: добавлены слова для расширения знака отрицательных чисел. Больше опкодов. Исправлена ошибка в реестре назначений. Комментарии. Все еще работаю над флагами и заполняю операторов. Вывод предоставляет несколько вариантов: вывод текста в стандартный вывод по окончании, непрерывный вывод с использованием кодов vt100, вывод в окно изображения с использованием шрифта CP437.
редактирование: закончена запись, начата отладка. Он получает первые четыре точки вывода! Тогда перенос идет не так. Сонный.
редактировать: я думаю, у меня есть отсортированный флаг переноса. Часть истории произошла на comp.lang.postscript . Я добавил несколько устройств отладки, и выходные данные отправляются в графическое окно (используя мой ранее написанный шрифт Code-Type-3 ), поэтому текстовый вывод может быть полон трасс и дампов. Там написано "Привет, мир!" а затем есть эта подозрительная карета. Тогда совсем ничего. :( Мы доберемся туда. Спасибо за поддержку!
редактировать: запускает тест до завершения. Последними ошибками были следующие: XCHG делал 2 {read store} повторения, которые, конечно, копируют, а не обменивает, И не устанавливает флаги, (FE) INC пытается получить слово из байтового указателя.
редактировать: Всего переписать с нуля, используя краткую таблицу из руководства ( перевернул новую страницу! ). Я начинаю думать, что вычеркнуть магазин из кодов операций было плохой идеей, но это помогло сохранить привлекательность оптаба. На этот раз нет скриншота. Я добавил счетчик команд и мод-триггер для выгрузки видеопамяти, чтобы она легко чередовалась с информацией отладки.
edit: снова запускает тестовую программу! Последние несколько ошибок для более короткого переписывания пренебрегали расширением знака непосредственного байта в кодах операций 83 (группа «Немедленно») и EB (короткий JMP). 24-строчное увеличение охватывает дополнительные процедуры отладки, необходимые для отслеживания этих последних ошибок.
И вывод (с хвостом сокращенного вывода отладки).
источник
Javascript
Я пишу эмулятор 486 в javascript, вдохновленный jslinux. Если бы я знал, сколько это будет стоить, я бы, наверное, никогда бы не начал, но теперь я хочу закончить.
Затем я столкнулся с вашим вызовом и был очень счастлив иметь программу 8086 для тестирования.
Вы можете «увидеть» его в прямом эфире здесь: http://codinguncut.com/jsmachine/
У меня была одна проблема при печати графического буфера. Там, где должны быть пробелы, память содержит элементы «00». Правильно ли интерпретировать «0x00» как пробел или в моем эмуляторе есть ошибка?
Ура,
Johannes
источник
C ++
Я хотел бы представить нашу запись для этого вызова кода. Он был написан на c ++ и отлично запускает тестовую программу. Мы внедрили 90% однобайтовых операционных кодов и базовой сегментации (некоторые отключены, поскольку они не работают с тестовой программой).
Программа написания: http://davecarruth.com/index.php/2012/04/15/creating-an-8086-emulator
Вы можете найти код в zip-файле в конце записи блога.
Скриншот выполнения тестовой программы:
Это заняло довольно много времени ... если у вас есть какие-либо вопросы или комментарии, не стесняйтесь сообщать мне. Это было, безусловно, отличное упражнение в партнерском программировании.
источник
ret imm
инструкция неверна (см. Здесь ), и вы пропустили0xff
группу. Мне нравятся ваши сообщения об ошибках: throw "Немедленное значение не может сохранить значение, замедляется.";cs
регистрС
Великий вызов и мой первый. Я создал аккаунт только потому, что этот вызов меня заинтриговал. Недостатком является то, что я не мог перестать думать о проблеме, когда у меня была настоящая, платная, программистская работа.
Я чувствую себя обязанным запустить законченную эмуляцию 8086, но это еще одна проблема ;-)
Код написан на ANSI-C, поэтому просто скомпилируйте / свяжите файлы .c вместе, передайте двоичный код codegolf и начинайте.
источник в архиве
источник
C ++ 1064 строки
Фантастический проект. Я делал эмулятор Intellivision много лет назад, так что было здорово снова сгибать мои бьющиеся мышцы.
Примерно через неделю работы я не мог быть более взволнован, когда это произошло:
Немного отладки позже и ... Шазам!
Кроме того, я перестроил оригинальную тестовую программу без расширений 80386, так как я хотел сделать свой эмулятор верным 8086, а не выдумывать какие-либо дополнительные инструкции. Прямая ссылка на код здесь: Zip файл .
Ладно, я слишком увлекаюсь этим. У меня отключилось управление памятью и экраном, и теперь экран обновляется при записи в экранный буфер. Я сделал видео :)
http://www.youtube.com/watch?v=qnAssaTpmnA
Обновления: первый этап сегментации. На самом деле реализовано очень мало инструкций, но я протестировал их, переместив CS / DS и SS, и все по-прежнему работает нормально.
Также добавлена элементарная обработка прерываний. Очень элементарно. Но я реализовал int 21h для печати строки. Добавил несколько строк в исходный текст теста и также загрузил его.
Если у кого-нибудь есть довольно простой ассемблерный код, который будет тестировать сегменты, я бы с удовольствием поиграл с ним.
Я пытаюсь понять, как далеко я хочу взять это. Полная эмуляция процессора? Режим VGA? Сейчас я пишу DOSBox.
12/6: Проверьте это, режим VGA!
источник
C ++ - 4455 строк
И нет, я не просто выполнил требования вопроса. Я сделал ВСЁ 8086, включая 16 никогда ранее не известных кодов операций. reenigne помог выяснить эти коды операций.
https://github.com/Alegend45/IBM5150
источник
#include "cpu.h"
трудно увидеть.Javascript - 4,404 строки
Я наткнулся на этот пост при поиске информации для моего собственного эмулятора. Этот пост Codegolf был абсолютно бесценным для меня. Программа-пример и связанная с ним сборка позволили легко отладить и посмотреть, что происходит.
Спасибо!!!
И вот первая версия моего эмулятора Javascript 8086.
Функции:
демонстрация
У меня есть демо онлайн, не стесняйтесь играть с ним, дайте мне знать, если вы найдете ошибки :)
http://js86emu.chadrempp.com/
Чтобы запустить программу Codegolf
1) нажмите на кнопку настроек
2) затем просто нажмите «загрузить» (здесь вы можете поиграть с параметрами отладки, например, пройтись по программе). Программа Codegolf является единственной доступной на данный момент, я работаю над тем, чтобы получить больше онлайн.
Источник
Полный источник здесь. https://github.com/crempp/js86emu
Я попытался вставить сюда эмуляцию 8086 здесь (как предложено doorknob), но она превысила ограничение на количество символов («Тело ограничено 30000 символами; вы ввели 158 272»).
Вот быстрая ссылка на код, который я собирался вставить здесь - https://github.com/crempp/js86emu/blob/39dbcb7106a0aaf59e003cd7f722acb4b6923d87/src/js/emu/cpus/8086.js
*Edit - updated for new demo and repo location
источник
Ява
Я так давно хотел сделать этот вызов, и я наконец нашел время, чтобы сделать это. До сих пор это был замечательный опыт, и я горжусь тем, что наконец-то завершил его.
Источник
Исходный код доступен на GitHub на NeatMonster / Intel8086 . Я попытался документировать практически все с помощью руководства пользователя семейства holly 8086 .
Я намерен реализовать все недостающие коды операций и функции, так что вы можете проверить выпуск 1.0 для версии с только теми, которые требуются для этой задачи.
Большое спасибо @copy!
источник
Common Lisp - 580 loc (442 без пустых строк и комментариев)
Я использовал этот вызов в качестве предлога для изучения Common Lisp. Вот результат:
Вот вывод в Emacs:
Я хочу выделить три основные особенности. Этот код делает интенсивное использование макросов при выполнении инструкций, такие как
mov
,xchg
, и artithmetic операции. Каждая инструкция включаетdisasm-instr
вызов макроса. Это реализует разборку вместе с реальным кодом, используя глобальную переменную if over, установленную во время выполнения. Я особенно горжусь независимым от назначения подходом, используемым для записи значений в регистры и косвенные адреса. Макросы, реализующие инструкции, не заботятся о месте назначения, так как формы, объединенные для любой возможности, будут работать с универсальнымsetf
макросом Common Lisp.Код можно найти в моем репозитории GitHub . Ищите ветку «codegolf», так как я уже начал реализовывать другие функции 8086 в master. Я уже реализовал флаги переполнения и четности вместе с регистром FLAGS.
Есть три операции в этом не в 8086,
0x82
а0x83
версии логических операторов. Это было обнаружено очень поздно, и было бы довольно грязно удалить эти операции.Я хотел бы поблагодарить @ja за его версию Python, которая вдохновила меня на ранних этапах этого проекта.
источник
C -
319348 строкЭто более или менее прямой перевод моей программы Postscript на C. Конечно, использование стека заменяется явными переменными. Поля инструкции разбиты на переменные
o
- байт кода операции,d
- поле направления,w
- поле ширины. Если это инструкция «mod-reg-r / m», в нее записывается байт mr-rmstruct rm r
. Декодирование полей reg и r / m происходит в два этапа: вычисление указателя на данные и загрузка данных, повторное использование одной и той же переменной. Так что для чего-то вродеADD AX,BX
: сначала x - указатель на ax, а y - указатель на bx, затем x - содержимое (ax), а y - содержимое (bx). Для повторного использования переменной для разных типов требуется много приведения.Байт кода операции декодируется с помощью таблицы указателей функций. Каждое тело функции составлено с использованием макросов для повторно используемых частей.
DW
Макро присутствует во всех функциях кодов операций и декодируетd
иw
переменные изo
кода операции байт.RMP
Макро выполняет первый этап декодирования «MR-RM» байт, иLDXY
выполняет второй этап. Коды операций, в которых хранится результат, используютp
переменную для хранения указателя на местоположение результата иz
переменную для хранения значения результата. Флаги рассчитываются после вычисленияz
значения.INC
ИDEC
операции сохранения флага переноса перед использованием родовойMATHFLAGS
функции (как частьADD
илиSUB
submacro) и восстановить его после слов, чтобы сохранить Carry.Редактировать: исправлены ошибки!
Редактировать: расширен и прокомментирован. Когда
trace==0
теперь выводит команду ANSI move-to-0,0 при выгрузке видео. Так что это лучше имитирует фактическое отображение.BIGENDIAN
Вещь (которая даже не работает) было удалено. В некоторых местах он основан на порядке байтов с прямым порядком байтов, но я планирую исправить это в следующей ревизии. В принципе, все доступы указателя должны пройти черезget_
иput_
функции , которые явно (де) составляют байты в LE порядке.Использование макросов для этапов различных операций обеспечивает очень близкое семантическое соответствие с тем, как код постскриптума работает чисто последовательным образом. Например, первые четыре кода операции, 0x00-0x03, являются инструкциями ADD с переменным направлением (REG -> REG / MOD, REG <- REG / MOD) и размерами байтов / слов, поэтому они представлены одинаково в таблице функций. ,
Таблица функций создается с помощью этого макроса:
который применяется
OPF()
к каждому представлению кода операции.OPF()
определяется как:Итак, первые четыре кода операции расширяются (один раз) до:
Эти функции различаются по результату
DW
макроса, который определяет направление и биты байта / слова прямо из байта кода операции. Развертывание тела одной из этих функций (один раз) приводит к:Где основной цикл уже установил
o
переменную:Развертывание еще раз дает все «мясо» кода операции:
И полностью предварительно обработанная функция, прошедшая через
indent
:Не самый лучший стиль C для повседневного использования, но использование макросов таким образом кажется довольно идеальным для того, чтобы сделать реализацию здесь очень короткой и очень прямой.
Вывод тестовой программы с выводом трассы:
Я поделился некоторыми более ранними версиями в comp.lang.c, но они не были очень заинтересованы.
источник
indent
под ред 5810 строк.