Важная информация

User Tag List

Страница 4 из 14 ПерваяПервая 12345678 ... ПоследняяПоследняя
Показано с 31 по 40 из 133

Тема: Ядро с 32 битами и виртуализацией

  1. #31

    Регистрация
    14.04.2013
    Адрес
    г. Ростов-на-Дону
    Сообщений
    608
    Спасибо Благодарностей отдано 
    70
    Спасибо Благодарностей получено 
    54
    Поблагодарили
    48 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от blackmirror Посмотреть сообщение
    Если народ уже добрался до команд длиной по 8 байт
    Народ экспериментирует Есть и однобайтные.

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

    Не совсем понял что с чем соединить, но по-моему это называется VLIW. У него ещё одна проблема есть, кроме ширины шин: кто это программировать будет? Или человек с особой усидчивостью, или оптимизирующий ассемблер, но кто ж его напишет. Был такой процессор Transmeta Crusoe. Неплохой, но "не взлетел". Нативно программировать его было некому, а в эмуляции x86 он по понятным причинам проигрывал этому самому x86.

    - - - Добавлено - - -

    Почему инструкция 8 байт? Да она и 20 может быть при таком подходе.

    Например, есть массив 32-разрядных значений, и в них надо установить бит с номером, равным номеру элемента.
    В цикле выполнить такое:
    Код:
       bset (IX+BC*4),BC
    Или, например, сортировка.
    Сравнить два значения в массиве, номера элементов заданы в BC и DE:
    Код:
       cp (IX+BC*2),(IX+DE*2)
    Переход по таблице:
    Код:
       jp (BC*4+label)
    Скопировать массив, в цикле:
    Код:
       ld (IX++),(IY++)
    Программист пишет так, дальше уже пусть ассемблер и процессор разбираются как это закодировать и как выполнить.

  2. #31
    С любовью к вам, Yandex.Direct
    Размещение рекламы на форуме способствует его дальнейшему развитию

  3. #32

    Регистрация
    25.11.2015
    Адрес
    г. Москва
    Сообщений
    192
    Спасибо Благодарностей отдано 
    12
    Спасибо Благодарностей получено 
    16
    Поблагодарили
    14 сообщений
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Еще некоторые соображения:

    Сейчас возможности плис позволяют многое делать за 1 такт, но оно может может оказаться слишком дорогим по ресурсам, если в систему команд тащить всё подряд.
    Первое, что нужно - это счётчик команд и механизм его увеличения. Последним может заниматься и ALU, у него будет достаточно времени, если шины адреса и данных не разделены. Но взглянув на обмен по шине, мы быстро придём к выводу, что так жить нельзя:
    Addr Prog
    Addr Prog Addr Rdata
    Addr Prog Addr Wdata
    Addr Prog Addr Rdata Wdata
    Поэтому адрес и данные нужно разделить чтобы удвоить скорость. Но мы опять с тоской посмотрим на шину, поскольку половину времени занимает чтение программы.

    Далее можно сделать или отдельную память и шину для чтения или кеш для программы. Можно даже прямого отображения, когда младшие разряды адреса однозначно выбирают вполне конкретную ячейку кеша и связанный с ней флаг.
    Еще потребуется поделить кеш на части и назначить каждой свой тег, который будет сравниваться со старшими разрядами адреса команды.
    Если тег совпадает и стоит флаг, значит инструкция выбирается из кеша, если тег не совпадает, то он перезаписывается, флаги сбрасываются, инструкция выбирается из памяти, записывается в кеш и устанавливается её флаг.
    Если хочется самомодифицируемый код, то придётся еще отслеживать запись, и хотя бы сбрасывать флаги записываемых ячеек. Можно и перезаписывать, но вдруг по этим адресам живёт ПЗУ и ничего не получится?!

    Наличие небольшого кеша позволит коротким циклам читать программу только на первой итерации, после чего операции с памятью смогут выполняться на 1 такт быстрее, за счёт отсутсвия необходимости читать программу.
    Еще одна полезная фича - это регистры LoopStart, LoopEnd, LoopCnt, для организации аппаратных циклов. Смысл в том, что когда счётчик команд совпадает с LoopEnd мы будем заменять его на LoopStart, если LoopCnt>0 уменьшив при этом последний. Таким образом для циклов с фиксированным числом итераций не нужна будет инструкция сравнения и команда условного перехода.

    Теперь нужно определиться, сколько внутри будет шин между регистрами и ALU, если две шины чтения операндов и одна записи результата плюс мультиплексор шин памяти, то за 1 такт можно выполнять следующие операции:
    Ri=Rj+Rk - шина памяти не используется
    Ri=Rj+(Rk) - регистр суммируется со значением из памяти, свободных шин для модификации адреса нет
    Ri=(Rj+Rk) - адрес берётся после ALU, данные читаются в регистр
    R0=(Ri), Ri+=Rj - все шины ALU используется для модификации адреса, поэтому данные записываются из памяти в фиксированный регистр
    (Ri)=Rj, Ri+ - регистр записывается в память, приращение адреса можно взять только из кода команды
    (Ri)=R0, Ri+=Rj - все шины ALU используется для модификации адреса, поэтому пишем фиксированный регистр
    (Ri)+=Rj, Ri+ - чтение/модификация/запись, два буферных регистра на шину памяти позволят параллельно с записью выполнять следующую команду формата Ri=Rj+Rk
    Ri=(Rj), (Rj)+=Rk - аналогично предыдущему, но если адрес не модифицировать, можно сохранить старое значение из ячейки памяти

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

    Этот пользователь поблагодарил blackmirror за это полезное сообщение:

    Bolt(19.01.2020)

  4. #33

    Регистрация
    14.04.2013
    Адрес
    г. Ростов-на-Дону
    Сообщений
    608
    Спасибо Благодарностей отдано 
    70
    Спасибо Благодарностей получено 
    54
    Поблагодарили
    48 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от blackmirror Посмотреть сообщение
    Сейчас возможности плис позволяют многое делать за 1 такт, но оно может может оказаться слишком дорогим по ресурсам, если в систему команд тащить всё подряд.
    Первое, что нужно - это счётчик команд и механизм его увеличения. Последним может заниматься и ALU, у него будет достаточно времени, если шины адреса и данных не разделены. Но взглянув на обмен по шине, мы быстро придём к выводу, что так жить нельзя:
    ...
    Счётчик команд считает сам, никаких ALU. Указатель стека тоже. Регистры inc/dec через отдельный блок.
    Взглянуть на обмен по шине... У меня SDRAM, процессор с MMU, и видеовыход VGA в той же куче, куда смотреть?
    У процессора нет параллельной шины, есть кэш на двухпортовой памяти, с одной стороны с ней работает процессор, с другой - контроллер SDRAM. Внешняя параллельная шина может и будет, но не скоро.
    Кэш кода и данных раздельно. Про теги и прочее знаю. Кэш работает, но с ошибками, отладить надо.
    Запись будет отслеживаться, самомодифицируемый код должен работать. Про ПЗУ хорошая мысль, надо запомнить.

    Цитата Сообщение от blackmirror Посмотреть сообщение
    Еще одна полезная фича - это регистры LoopStart, LoopEnd, LoopCnt, для организации аппаратных циклов. Смысл в том, что когда счётчик команд совпадает с LoopEnd мы будем заменять его на LoopStart, если LoopCnt>0 уменьшив при этом последний. Таким образом для циклов с фиксированным числом итераций не нужна будет инструкция сравнения и команда условного перехода.
    Я против. Чем djnz не устраивает? Давайте её сделаем для любых регистров.
    А с дополнительными регистрами мало того что усложняется процессор, так потом ещё думать что с ними делать во вложенных циклах и в прерываниях. А ещё держим в уме многозадачность.

    Цитата Сообщение от blackmirror Посмотреть сообщение
    Теперь нужно определиться, сколько внутри будет шин между регистрами и ALU, если две шины чтения операндов и одна записи результата плюс мультиплексор шин памяти, то за 1 такт можно выполнять следующие операции:
    ...
    Список операций скопировал в блокнотик, потом подумаю.
    С шинами всё сложно, пока не определился.
    Есть как бы шина чтения регистров, и как бы шина записи. Это два глобальных мультиплексора, плюс несколько мелких. Блоки чтения-записи данных и чтения кода каждый отдельно, у них там свои шины и временные регистры.

    - - - Добавлено - - -

    Основных регистров будет 9: BC, DE, HL, резерв, IX, IY, IZ, I_резерв, и отдельно аккумулятор. Резервным регистрам название пока не придумал, для чего они нужны - тоже. Просто регистры. I_резерв может будет типа BP, с быстрым доступом к локальным переменным.

    Система команд практически "всё со всем".
    Первый операнд: A, регистр, память.
    Второй операнд, если нужен: то же, и ещё константа.
    Память: [BC,DE,HL]*[1,2,4]+[IX,IY,IZ]+const. Всё опционально.
    Функции: те же, что у Z80.

    Что из этого сделать одним байтом, а что с префиксами - пока думаю.
    Что получится за один такт тоже пока не знаю, это станет понятно когда до Verilog-а доберусь.

    На данный момент однобайтные:
    inc/dec A/R
    mov A,R
    mov R,A
    одноместные с аккумулятором (сдвиги, инверсия)

    Думаю о push/pop. Можно и их сделать однобайтными, но они вроде не так часто используются.
    Djnz тоже тогда однобайтной сделать. А может "dec / jpnz" обойдёмся?

    - - - Добавлено - - -

    Во, резервный для данных будет MN, а резервный индексный IV - vars. И можно сделать укороченный вариант опкодов для "func A,(IV+offset)".
    Последний раз редактировалось Bolt; 19.01.2020 в 00:13.

  5. #34

    Регистрация
    14.04.2013
    Адрес
    г. Ростов-на-Дону
    Сообщений
    608
    Спасибо Благодарностей отдано 
    70
    Спасибо Благодарностей получено 
    54
    Поблагодарили
    48 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Попробовал. IV вообще в коде не воспринимается. То ли половинка от X, то ли римская 4. И если бегло просматривать с IX можно спутать.

    Может IS? Какие ещё буквы свободны?

    add A,(IS+0x34)

  6. #35

    Регистрация
    25.11.2015
    Адрес
    г. Москва
    Сообщений
    192
    Спасибо Благодарностей отдано 
    12
    Спасибо Благодарностей получено 
    16
    Поблагодарили
    14 сообщений
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Bolt, даже если внешней шины нет, значит есть шина кеша и она для нас и играет роль памяти. Правильно ли я понимаю, что каждый порт этой памяти имеет шину адреса, прочитанных данных и данных для записи, но одновременно прочитать и записать через один порт мы не сможем?
    По сравнению с djnz аппаратные циклы хороши тем, что кроме инициализации не имеют других накладных расходов, для снижения которых не требуется делать разворот в случае малого количества команд. К примеру если тело цикла из одной команды, добавление djnz снизит его производительность в 2 раза, а когда мы его развернём, нужен будет дополнительный код, чтобы определить сколько полных блоков и сколько итераций в хвосте.
    Во всяких Cortex команды push и pop в качестве аргумента имеют битовую маску какие регистры сохранять/загружать, а какие пропустить. Есть команды загрузки сохранения аналогичные pop и для других регистров. И еще есть команда загружающая/сохраняющая сразу по 2 произвольных регистра то есть: Ri=(Ra) Rj=(Ra+4) Ra+=8.

    Дополнительные размышления привели меня к мысли, что для обращения к памяти сложные формы адресации не требуются.
    Требуется поделить банк регистров на чётные и нечётные, поставить два ALU, две шины записи и 4 шины чтения, и в коде команды указывать что подать на мультиплексоры для этих шин. Для записи в память несколько бит будут выбирать с какой из шин выдать адрес и данные. Для чтения нужно выбрать с какой шины выдавать адрес, и нужно ли прочитанные данные поместить в фиксированный регистр или выдать на шину записи. В итоге в 32 бита команды можно закодировать две регистровые операции по 12-13 бит и одну пересылку 5-6 бит, в достаточно ортогональном для удобства программирования виде.
    Последний раз редактировалось blackmirror; 19.01.2020 в 14:30.

    Этот пользователь поблагодарил blackmirror за это полезное сообщение:

    Bolt(19.01.2020)

  7. #36

    Регистрация
    14.04.2013
    Адрес
    г. Ростов-на-Дону
    Сообщений
    608
    Спасибо Благодарностей отдано 
    70
    Спасибо Благодарностей получено 
    54
    Поблагодарили
    48 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от blackmirror Посмотреть сообщение
    Правильно ли я понимаю, что каждый порт этой памяти имеет шину адреса, прочитанных данных и данных для записи, но одновременно прочитать и записать через один порт мы не сможем?
    Да, правильно.

    Цитата Сообщение от blackmirror Посмотреть сообщение
    К примеру если тело цикла из одной команды, добавление djnz снизит его производительность в 2 раза
    А если выполнять по 2 команды за такт, то цикл из одной команды замедлится в 3 раза
    Нет, идея с регистрами мне не нравится. И в любом случае переход сбивает буфер инструкций (конвейер). Потом может для циклов придумаю что-нибудь.

    Цитата Сообщение от blackmirror Посмотреть сообщение
    Дополнительные размышления привели меня к мысли, что для обращения к памяти сложные формы адресации не требуются.
    Пусть будут, они не мешают. Load/store архитектура тоже имеет недостатки.

    Цитата Сообщение от blackmirror Посмотреть сообщение
    Во всяких Cortex команды push и pop в качестве аргумента имеют битовую маску какие регистры сохранять/загружать, а какие пропустить. Есть команды загрузки сохранения аналогичные pop и для других регистров. И еще есть команда загружающая/сохраняющая сразу по 2 произвольных регистра то есть: Ri=(Ra) Rj=(Ra+4) Ra+=8.
    Цитата Сообщение от blackmirror Посмотреть сообщение
    Требуется поделить банк регистров на чётные и нечётные, поставить два ALU, две шины записи и 4 шины чтения, и в коде команды указывать что подать на мультиплексоры для этих шин. Для записи в память несколько бит будут выбирать с какой из шин выдать адрес и данные. Для чтения нужно выбрать с какой шины выдавать адрес, и нужно ли прочитанные данные поместить в фиксированный регистр или выдать на шину записи. В итоге в 32 бита команды можно закодировать две регистровые операции по 12-13 бит и одну пересылку 5-6 бит, в достаточно ортогональном для удобства программирования виде.
    Для такого двойного процессора программист будет писать две команды в строке, или ассемблер соберёт две в одну? Потому что проектировать процессор с блокировками и байпасами меня что-то совсем не прёт.

    Разделение регистров позволяет и push сделать по маске, и два ALU с двумя операциями за такт, но я на данный момент вообще не понимаю как эту параллельность воткнуть в то, что есть. При 32-битных командах RISC всё получается просто, но надо сохранить совместимость с Z80, а он совсем не RISC, переменная длина команд всё портит. Предел, на котором по-моему надо остановиться - один байт кода за такт.

    По тактам минимум получается примерно так:
    mov A,R - 1 такт
    mov R,A - 1 такт
    mov R,R - 2 такта
    func A - 1 такт
    func R - 2 такта
    func A,R - 3 такта
    func R,A - 4 такта
    func A,imm32 - 6 байт, 8 тактов
    func [reg],imm32 - 7 байт, 17 тактов

    Доступ к памяти пока по 1 байту, поэтому так долго. Можно, конечно, и внутреннюю шину сделать 32 бита, и не ждать окончания записи, и что-то распараллелить, всё можно. Но я тогда закопаюсь в этих деталях и до главного - запуска процессора - не доберусь.

  8. #37

    Регистрация
    25.11.2015
    Адрес
    г. Москва
    Сообщений
    192
    Спасибо Благодарностей отдано 
    12
    Спасибо Благодарностей получено 
    16
    Поблагодарили
    14 сообщений
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Bolt Посмотреть сообщение
    А если выполнять по 2 команды за такт, то цикл из одной команды замедлится в 3 раза
    Нет, идея с регистрами мне не нравится. И в любом случае переход сбивает буфер инструкций (конвейер). Потом может для циклов придумаю что-нибудь.
    Конвейер сбивают непредсказанные переходы, а аппаратные циклы штука вполне предсказуемая.

    Цитата Сообщение от Bolt Посмотреть сообщение
    Для такого двойного процессора программист будет писать две команды в строке, или ассемблер соберёт две в одну? Потому что проектировать процессор с блокировками и байпасами меня что-то совсем не прёт.
    Можно либо ставить специальный знак, что к данной строке нужно прицепить команду из следующей, но мне больше нравится вариант продолжать команды в той же строке.

    Цитата Сообщение от Bolt Посмотреть сообщение
    Разделение регистров позволяет и push сделать по маске, и два ALU с двумя операциями за такт, но я на данный момент вообще не понимаю как эту параллельность воткнуть в то, что есть. При 32-битных командах RISC всё получается просто, но надо сохранить совместимость с Z80, а он совсем не RISC, переменная длина команд всё портит. Предел, на котором по-моему надо остановиться - один байт кода за такт.
    С переменной длинной может помочь только двоичная перекомпиляция, но наверно действительно лучше остановиться.

  9. #38

    Регистрация
    20.04.2006
    Адрес
    Санкт-Петербург
    Сообщений
    2,870
    Спасибо Благодарностей отдано 
    521
    Спасибо Благодарностей получено 
    251
    Поблагодарили
    225 сообщений
    Mentioned
    8 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Да уж, не ASIC запускаете в тираж. Посему можно иметь в дальнейшем хоть дюжину более сложных и более совершенных версий архитектуры. Выдайте "на гора" что-то лучшее чем имеющееся и это уже будет успех!

  10. #39

    Регистрация
    14.04.2013
    Адрес
    г. Ростов-на-Дону
    Сообщений
    608
    Спасибо Благодарностей отдано 
    70
    Спасибо Благодарностей получено 
    54
    Поблагодарили
    48 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от blackmirror Посмотреть сообщение
    С переменной длинной может помочь только двоичная перекомпиляция, но наверно действительно лучше остановиться.
    О двоичной перекомпиляции тоже думал, в итоге остановился на таком вот гибридном процессоре.

    - - - Добавлено - - -

    Цитата Сообщение от andrews Посмотреть сообщение
    можно иметь в дальнейшем хоть дюжину более сложных и более совершенных версий архитектуры.
    Ага. Только желательно сохранить совместимость по коду.

  11. #40

    Регистрация
    14.04.2013
    Адрес
    г. Ростов-на-Дону
    Сообщений
    608
    Спасибо Благодарностей отдано 
    70
    Спасибо Благодарностей получено 
    54
    Поблагодарили
    48 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Вариант для циклов.

    Сделать не djnz, а djz. Тогда цикл можно развернуть так:
    Код:
       ld BC,1234
    loop:
       ...
       djz BC,exit
       ...
       djz BC,exit
       ...
       djz BC,exit
       ...
       djz BC,exit
       jp loop
    exit:
    А разворачивать может и ассемблер, типа dup.

Страница 4 из 14 ПерваяПервая 12345678 ... ПоследняяПоследняя

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Похожие темы

  1. Ответов: 465
    Последнее: 03.01.2020, 07:15
  2. Ответов: 16
    Последнее: 02.08.2005, 12:20

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •