14:39 13.03.2013
Пилим восьмибитный процессор. Часть шестая: улучшение архитектуры и снова ассемблер.
Пилим восьмибитный процессор. Часть шестая: улучшение архитектуры и снова ассемблер.
После вынужденного перерыва снова возвращаюсь к своей архиувлекательной разработке. Оставил я её в каком-то промежуточном состоянии: например, минимальный набор команд реализован, возможность менять значения в памяти есть - а перехода на нужный адрес нет (хотя всё необходимое для реализации такой команды есть, саму команду я не запилил).
Непорядок.
В общем, я достаточно долго думал и прикидывал, что делать дальше, и как лучше это что делать. Пришёл к следующему выводу: нужно менять структуру команд, пилить уже условные переходы и циклы. После этого - уже всё, настоящий хардкор.
Что плохо в текущих командах? Они были взяты от балды, и шли не в логическом порядке: скажем за логическим XOR шло арифметическое SUM, потом опять логический SHL. Добавь я сейчас команду SUB (вычитание) - её пришлось бы помещать вновь за логической командой, а не рядом с SUM, где ей самое место. Нет, если пользоваться ассемблером - то пофиг, в каком порядке идут опкоды, но при трейсе обработки команд с упорядоченными командами удобнее.
Дальше: команда NOP. Много ли можно придумать программ, где ничего не делающий операнд реально нужен? В крайнем случае для пропуска такта можно использовать MOV A,A.
Итого я пересмотрел набор команд, и выглядит теперь он так:
Описание команд переходов и работы со стеком чуть ниже.
Как видите - изменился и набор и порядок. При этом пока четыре опкода остаются свободными - я даже не знаю, какие команды можно ими задать. Возможно, при расширении архитектуры появятся какие-то команды (например опкод, выводящий "Hello, world!", таким образом, делающий возможным написание такой программы размером в один байт).
Думаю, с опкодами 0x1 - 0xA вопросов не возникло. Другое дело - 0x0, обозначающий различные переходы по памяти. Как одной командой можно закодировать их все?
Тут стоит вспомнить, как переходы реализованы в x86. Самый простой, безусловный переход вызывается так:
Соответственно, команда в памяти представлена двумя последовательностями бит: одна кодирует команду JMP, другая шифрует адрес. Просто и логично.
( Read more... )
Непорядок.
В общем, я достаточно долго думал и прикидывал, что делать дальше, и как лучше это что делать. Пришёл к следующему выводу: нужно менять структуру команд, пилить уже условные переходы и циклы. После этого - уже всё, настоящий хардкор.
Что плохо в текущих командах? Они были взяты от балды, и шли не в логическом порядке: скажем за логическим XOR шло арифметическое SUM, потом опять логический SHL. Добавь я сейчас команду SUB (вычитание) - её пришлось бы помещать вновь за логической командой, а не рядом с SUM, где ей самое место. Нет, если пользоваться ассемблером - то пофиг, в каком порядке идут опкоды, но при трейсе обработки команд с упорядоченными командами удобнее.
Дальше: команда NOP. Много ли можно придумать программ, где ничего не делающий операнд реально нужен? В крайнем случае для пропуска такта можно использовать MOV A,A.
Итого я пересмотрел набор команд, и выглядит теперь он так:
Опкод | Команда | Описание |
---|---|---|
0x0 | MEM | Переходы по памяти |
0x1 | MOV | Пересылка значения |
0x2 | XOR | Логическое ИЛИ-НЕ |
0x3 | OR | Логическое ИЛИ |
0x4 | AND | Логическое И |
0x5 | SHL | Левое смещение |
0x6 | SHR | Правое смещение |
0x7 | SUM | Арифметическое сложение |
0x8 | SUB | Арифметическое вычитание |
0x9 | MUL | Арифметическое умножение |
0xA | DIV | Арифметическое деление |
0xB | STACK | Работа со стеком |
Как видите - изменился и набор и порядок. При этом пока четыре опкода остаются свободными - я даже не знаю, какие команды можно ими задать. Возможно, при расширении архитектуры появятся какие-то команды (например опкод, выводящий "Hello, world!", таким образом, делающий возможным написание такой программы размером в один байт).
Думаю, с опкодами 0x1 - 0xA вопросов не возникло. Другое дело - 0x0, обозначающий различные переходы по памяти. Как одной командой можно закодировать их все?
Тут стоит вспомнить, как переходы реализованы в x86. Самый простой, безусловный переход вызывается так:
JMP @ADDRESSгде ADDRESS указывает на адрес в памяти, на который нужно совершить переход.
Соответственно, команда в памяти представлена двумя последовательностями бит: одна кодирует команду JMP, другая шифрует адрес. Просто и логично.
( Read more... )