Ynicky пишет: Если Вы имеете в виду реализацию вашего процессора (я думал, он у Вас уже сделан),
Сделан и даже работает, но на уровне прототипа прототипа. :)
Пока даже конвейера нет - реализовано "в лоб".
то есть некоторые сложности.
Поразбирался с системой команд.
Сразу нашлись проблемы с аппаратной реализацей процессора.
1. Возникнут сложности с определением начального байта инструкции при ошибке программирования,
Вот тут не согласен. Полная длина инструкции сейчас однозначно определяется по первому байту. Инструкция может быть расположена по любому выровненному или невыровненному адресу. Сложность может быть только при выборке инструкции из SDRAM, если инструкция находится в смежных ячейках. Но тут скорее сложность в организации выборки.
Без конвейера проблема решилась с помощью двухпортового кэша - два 32-х разрядных слова достаточно чтобы за один раз выбрать инструкция размером до 5-ти байт с любого адреса. Т.е. инструкция в 5 байт всегда помещается в два смежных 32-х битных слова.
так как система команд не фиксирована (нужен аппаратный анализ нескольких байтов инструкций).
Вот такая конструкция используется для анализа размера инструкции
wire [3:0] GetOperandSize =
(opcode[7:5] == 4'b000 ) ? 4'h1 :
(opcode[7] == 1'b0 ) ? 4'h2 :
(opcode[7:5] == 3'b111 ) ? 4'h5 :
(opcode[7:6] == 2'b11 ) ? 4'h4 : 4'h3;
Я сожалею за введение в заблуждение - по таблице инструкций эта инфаормация никак не следует.
2. Сложность реализации арифметико-логических команд с памятью, так как процессор не load/store.
Т.е. необходимо реализовать микрокод или эмулировать такие команды в несколько простых команд
(загрузка, операция АЛУ, выгрузка).
Да, к сожалению это так. В смысле сложности реализации. Я использовал сложный конечный автомат, который раскладывает сложные операции на стадии. Не конвейер, но работает. По хорошему нужно переделывать на конвейер.
А еще есть команды поддержки многозадачности (пока не разбирался с реализацией).
Именно ради многозадачности вся эта затея и затевалась. Поначалу (из за отсутствия опыта) хотелось всё сделать аппаратно, но реальность чуть обрезала крылья - инструкции для многозадачности вырождаются в подпрограммы в микрокоде. Но при этом используется симбиоз программной и аппаратной реализации.
Пока не реализовано, я старался не раскрывать детали. С Вашего позволения намекну как это выглядит. Регистровый файл поделен на сегменты, каждый сегмент соответствует задаче. Т.е. в текущей реализации число задач предопределено количеством сегментов в регистровом файле. В момент переключения задач переключается активный сегмент регисрового файла. Задача с номером 0 это планировщик. При выполнении некоторых инструкций их семантика отличается если они выполняются планировщиком или любой другой задачей.
Пока для управления задачами придумал, реализую и отлаживаю передачу сообщений планировщку. В этом случае параметр таймаута трактуется как идентификатор операции. Т.е. любая задача может послать сообщение планировщику и попросить его сделать одну из двух вещей - клонировать процесс или завершть задачу. Таким образом если какой-то процесс пошлёт сообщение планировщику с командой останова, то он будет выкинут из процедуры планирования а занятые им ресурсы будут помечены как свободные. А сообщение клонирования создаст копию задачи.
Конечная цель проекта - обеспечить возможность обмена синхронными сообщениями между задачами. Когда и если это будет достигнуто, то появится устройство с RTOS, некоторая часть которой реализована аппаратно, через симбиоз микрокода и аппаратной поддержи.
Я, как системщик (приходится выбирать компромисс между разработкой аппаратуры и программного
обеспечения), не уверен в том что справлюсь с аппаратной реализацией такого процессора.
До сих пор имел дело только с разработкой load/store RISC процессоров с фиксированной
длиной команд Гарвардской архитектуры. Да и пишу я на VHDL, а не на Verilog-е.
Имхо, в данном случае язык не принципиален. Особенно в свете того, что в пределах одного проекта Quartus позволяет смешивать разные языки.
В принципе, можно устроить небольшой "holywar" на предмет RISC vs CISC. Т.е. я твёрдо уверене что у CISC есть преимущество в виде более высокой плотности кода, а это значит кто кэш инструкицй используются более оптимально, более быстрее происхдит выборка из медленной динамической памяти. Если удастся удачно конвейеризировать операции, то у RISC останется только одно преимущество - RISC использует меньшее количество логических элементов.
А если говорить о Marsohod3, то с такле количество логических элементов позволяет мечтать о многоядерности. При этом открывается огромное поле для экспериментов по обиену сообщениями между ядрами.
Наконец, апофеозом этого должна стерется граница между софтом и железом - всё взаимодействие между задачами только с помощью сообщений, при этом абстракция "сообщение" скрывает физическую реализацию адресата - за идентификатором сообщения может скрываться программный thread на этом же ядре, задача на соседнем ядре, задача на соседнем процессоре в мультипроцессорной конфигурации или аппаратное устройство, специализированный сопроцессор - физическая реализация может быть скрыта за идентификатором задачи. Например, планировщика задач в результате из микрокода должен переехать в специализированный аппаратный блок. Но это, конечно, программа максимум - я не уверен что успею завершиь это за разумное время.
В общем, извините, что "тяну одеяло на себя" - скоро будет 15 лет как я познакомился и влюбился в микроядро L4 Pistachio и я действительно знаю как оптимально и эффективно использовать синхронные сообщения. Семафоры, мютексы, критические секции и прочие объекты синхронизации... они все будут нужны только для прикладного legacy софта. Синхронные сообщения - это базис на котором можно построить надёжную систему любой сложности. А если эти сообщения будут реализованы в железе, то это будет хорошим технологическим преимуществом.