Автор |
Сообщение |
|
|
Заголовок сообщения: |
Re: Конвейерный многоядерный процессор. |
|
|
A следующий вариант - это мультиядерный процессор с параметрически задаваемым количеством ядер: Код: -- шапка та же LIBRARY IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_unsigned.all; USE WORK.Common_lib.all; USE WORK.EQUINOX_lib.all;
entity EQUINOX_NE16 is generic( -- параметр - количество ядер N : integer := 8 -- number of CPU cores ); Port( clk,reset,ena : in node := vcc; addr : out word; do : out word; di : in word; mwr,mrd : out node; id : out byte; -- выход идентификатора ядра test_top,test_bot,test_pc,test_cmd : out word ); end EQUINOX_NE16;
architecture rtl of EQUINOX_NE16 is
-- создаем новый тип-массив из записей с регистрами процессорных ядер type cpus_t is array (1 to N) of cpu_t; -- объявляем сам массив signal cpus : cpus_t; -- вспомогательная переменная signal cpu : cpu_t; -- в схеме она набор отображающий -- состояние одного из ядер процессора, а не регистров
-- вспомогательные сигналы для запуска signal cnt_reset : int8; -- счетчик сброса signal rst : node; -- внутренний сброс
begin process (clk) begin if reset = gnd then -- по внешнему сбросу, устанавливаем внутренний -- сброс и счетчик наколичество ядер cnt_reset <= N; rst <= gnd; elsif clk'event and clk = vcc and ena = vcc then -- по тактам перебираем все ядра от N-го до первого if cnt_reset > 0 then -- пока счетчик не обнулился, cnt_reset <= cnt_reset - 1; rst <= gnd; --держим внутренний сброс else rst <= vcc; end if;
if rst = gnd then -- по внутреннему сбросу инициируем все ядра if cnt_reset /= 1 then -- все не первые стоят cpus(cnt_reset).id <= zero8+cnt_reset; cpus(cnt_reset).cmd <= stops; cpus(cnt_reset).pc <= zero16 + (cnt_reset - 1)*256; else -- а первое стартует с нулевого адреса cpus(cnt_reset).id <= zero8+cnt_reset; cpus(cnt_reset).cmd <= nops; cpus(cnt_reset).pc <= zero16; end if; else -- кольцо из ядер cpus(2 to N) <= cpus(1 to N-1); -- и логическое ядро cpus(1) <= equinox_main(cpus(N),di); end if; end if; -- вспомогательный набор регистров соотвтетствует ядру, которое -- через 2 такта будет ожидать свои данные на шине di cpu <= cpus(N-2); -- для него и выводим наружу адрес, данные, -- управляющие шины и идентификатор addr <= cpu.oadr; do <= cpu.odat; mwr <= cpu.mwr; mrd <= cpu.mrd; id <= cpu.id; end process; -- тестовые шины уже можно и выкинуть test_top <= cpu.dst.top; test_bot <= cpu.dst.bot; test_pc <= cpu.pc; test_cmd <= cpu.cmd; end; Такая вот, штучка.... И замечу, что Quartus при включении некоторых опций оптимизации сам начинает раскидывать логическое ядро по конвееру, что видно по увеличению тактовой частоты, на которую разводится проект. Без оптимизации начальная частота - 89MHz, a при ее включении, частота подымается до 144MHz еще без ручного раскидывания операций по конвейеру.
A следующий вариант - это мультиядерный процессор с параметрически задаваемым количеством ядер: [code] -- шапка та же LIBRARY IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_unsigned.all; USE WORK.Common_lib.all; USE WORK.EQUINOX_lib.all;
entity EQUINOX_NE16 is generic( -- параметр - количество ядер N : integer := 8 -- number of CPU cores ); Port( clk,reset,ena : in node := vcc; addr : out word; do : out word; di : in word; mwr,mrd : out node; id : out byte; -- выход идентификатора ядра test_top,test_bot,test_pc,test_cmd : out word ); end EQUINOX_NE16;
architecture rtl of EQUINOX_NE16 is
-- создаем новый тип-массив из записей с регистрами процессорных ядер type cpus_t is array (1 to N) of cpu_t; -- объявляем сам массив signal cpus : cpus_t; -- вспомогательная переменная signal cpu : cpu_t; -- в схеме она набор отображающий -- состояние одного из ядер процессора, а не регистров
-- вспомогательные сигналы для запуска signal cnt_reset : int8; -- счетчик сброса signal rst : node; -- внутренний сброс
begin process (clk) begin if reset = gnd then -- по внешнему сбросу, устанавливаем внутренний -- сброс и счетчик наколичество ядер cnt_reset <= N; rst <= gnd; elsif clk'event and clk = vcc and ena = vcc then -- по тактам перебираем все ядра от N-го до первого if cnt_reset > 0 then -- пока счетчик не обнулился, cnt_reset <= cnt_reset - 1; rst <= gnd; --держим внутренний сброс else rst <= vcc; end if;
if rst = gnd then -- по внутреннему сбросу инициируем все ядра if cnt_reset /= 1 then -- все не первые стоят cpus(cnt_reset).id <= zero8+cnt_reset; cpus(cnt_reset).cmd <= stops; cpus(cnt_reset).pc <= zero16 + (cnt_reset - 1)*256; else -- а первое стартует с нулевого адреса cpus(cnt_reset).id <= zero8+cnt_reset; cpus(cnt_reset).cmd <= nops; cpus(cnt_reset).pc <= zero16; end if; else -- кольцо из ядер cpus(2 to N) <= cpus(1 to N-1); -- и логическое ядро cpus(1) <= equinox_main(cpus(N),di); end if; end if; -- вспомогательный набор регистров соотвтетствует ядру, которое -- через 2 такта будет ожидать свои данные на шине di cpu <= cpus(N-2); -- для него и выводим наружу адрес, данные, -- управляющие шины и идентификатор addr <= cpu.oadr; do <= cpu.odat; mwr <= cpu.mwr; mrd <= cpu.mrd; id <= cpu.id; end process; -- тестовые шины уже можно и выкинуть test_top <= cpu.dst.top; test_bot <= cpu.dst.bot; test_pc <= cpu.pc; test_cmd <= cpu.cmd; end;[/code]
Такая вот, штучка....
И замечу, что Quartus при включении некоторых опций оптимизации сам начинает раскидывать логическое ядро по конвееру, что видно по увеличению тактовой частоты, на которую разводится проект.
Без оптимизации начальная частота - 89MHz, a при ее включении, частота подымается до 144MHz еще без ручного раскидывания операций по конвейеру.
|
|
|
|
Добавлено: Ср мар 14, 2012 19:53 |
|
|
|
|
|
Заголовок сообщения: |
Re: Конвейерный многоядерный процессор. |
|
|
Следующий шаг - это шестиядерный конвейерный вариант. Тут, собственно, интересно только это: Начальная схема, где конвейера еще и нет: Код: rchitecture rtl of EQUINOX_6E16 is
--attribute altera_attribute : string; -- Attribute set on architecture, not entity --attribute altera_attribute of rtl: architecture is "-name AUTO_SHIFT_REGISTER_RECOGNITION OFF";
signal cpu : cpu_t; signal cpu1,cpu2,cpu3,cpu4,cpu5,cpu6 : cpu_t;
begin process (clk) begin if reset = gnd then cpu1.pc <= zero16; cpu2.pc <= zero16+256; cpu3.pc <= zero16+512; cpu4.pc <= zero16+768; cpu5.pc <= zero16+1024; cpu6.pc <= zero16+1280; cpu1.cmd <= zero16; cpu2.cmd <= stops; cpu3.cmd <= stops; cpu4.cmd <= stops; cpu5.cmd <= stops; cpu6.cmd <= stops; elsif clk'event and clk = vcc and ena = vcc then cpu1 <= equinox_main(cpu8,di); cpu2 <= cpu1; cpu3 <= cpu2; cpu4 <= cpu3; cpu5 <= cpu4; cpu6 <= cpu5; end if; cpu <= cpu4;
addr <= cpu.oadr; do <= cpu.odat; mwr <= cpu.mwr; mrd <= cpu.mrd; id <= cpu.id; end process; test_top <= cpu.dst.top; test_bot <= cpu.dst.bot; test_pc <= cpu.pc; test_cmd <= cpu.cmd; Здесь важно для понимания, что выходные шины подключены не к первому ядру, как в трехядерном варианте, а к 4му, что обеспечивает появление адреса для памяти за 2 такта до момента, когда будут нужны соответствующие данные. Вот тут, как раз, и возникает возможность повышения тактовой частоты процессора, если логику раскинуть на шесть ступеней конвейера. В схеме выше, можно сказать, что пять из шести ступеней конвейера просто ничего не делают, а все делается одной ступенью. Такое построение позволяет легко проследить логику работы кольца ядер, чтобы перейти к следующему варианту схемы...
Следующий шаг - это шестиядерный конвейерный вариант.
Тут, собственно, интересно только это:
Начальная схема, где конвейера еще и нет:
[code]rchitecture rtl of EQUINOX_6E16 is
--attribute altera_attribute : string; -- Attribute set on architecture, not entity --attribute altera_attribute of rtl: architecture is "-name AUTO_SHIFT_REGISTER_RECOGNITION OFF";
signal cpu : cpu_t; signal cpu1,cpu2,cpu3,cpu4,cpu5,cpu6 : cpu_t;
begin process (clk) begin if reset = gnd then cpu1.pc <= zero16; cpu2.pc <= zero16+256; cpu3.pc <= zero16+512; cpu4.pc <= zero16+768; cpu5.pc <= zero16+1024; cpu6.pc <= zero16+1280; cpu1.cmd <= zero16; cpu2.cmd <= stops; cpu3.cmd <= stops; cpu4.cmd <= stops; cpu5.cmd <= stops; cpu6.cmd <= stops; elsif clk'event and clk = vcc and ena = vcc then cpu1 <= equinox_main(cpu8,di); cpu2 <= cpu1; cpu3 <= cpu2; cpu4 <= cpu3; cpu5 <= cpu4; cpu6 <= cpu5; end if; cpu <= cpu4;
addr <= cpu.oadr; do <= cpu.odat; mwr <= cpu.mwr; mrd <= cpu.mrd; id <= cpu.id; end process; test_top <= cpu.dst.top; test_bot <= cpu.dst.bot; test_pc <= cpu.pc; test_cmd <= cpu.cmd; [/code]
Здесь важно для понимания, что выходные шины подключены не к первому ядру, как в трехядерном варианте, а к 4му, что обеспечивает появление адреса для памяти за 2 такта до момента, когда будут нужны соответствующие данные.
Вот тут, как раз, и возникает возможность повышения тактовой частоты процессора, если логику раскинуть на шесть ступеней конвейера. В схеме выше, можно сказать, что пять из шести ступеней конвейера просто ничего не делают, а все делается одной ступенью. Такое построение позволяет легко проследить логику работы кольца ядер, чтобы перейти к следующему варианту схемы...
|
|
|
|
Добавлено: Ср мар 14, 2012 19:37 |
|
|
|
|
|
Заголовок сообщения: |
Re: Конвейерный многоядерный процессор. |
|
|
И поэтому я делаю следующий шаг. В схему добавляются еще два набора регистров процессора, и все три набора включаются в кольцо: Опускаю шапку и конец исходника, которые фактически не меняются. Измененная часть: Код: architecture rtl of EQUINOX_3E16 is
-- signal cpu : cpu_t; -- три совершенно одинаковых набора регистров signal cpu1,cpu2,cpu3 : cpu_t;
begin process (clk) begin if reset = gnd then -- по сбросу все счетчики команд устанавливаются на разные адреса cpu1.pc <= zero16; cpu2.pc <= zero16+256; cpu3.pc <= zero16+512; cpu1.cmd <= zero16; -- первое ядро стартует с NOP-ов cpu2.cmd <= stops; -- два других cpu3.cmd <= stops; -- остановлены elsif clk'event and clk = vcc and ena = vcc then -- кольцо из трех наборов регистров с одним логическим ядром cpu1 <= equinox_main(cpu3,di); cpu2 <= cpu1; cpu3 <= cpu2; end if;
На вход ena в такой схеме уже можно смело подавать логическую единицу, и все три ядра заработают на частоте 1/3 от частоты clk... Собственно, в симуляторе это хорошо видно. Картинки не привожу, потому что кто сам с усам, тот их сам легко получит, а кому все это не интересно, тому и картинки не интересны.
И поэтому я делаю следующий шаг.
В схему добавляются еще два набора регистров процессора, и все три набора включаются в кольцо:
Опускаю шапку и конец исходника, которые фактически не меняются. Измененная часть: [code] architecture rtl of EQUINOX_3E16 is
-- signal cpu : cpu_t; -- три совершенно одинаковых набора регистров signal cpu1,cpu2,cpu3 : cpu_t;
begin process (clk) begin if reset = gnd then -- по сбросу все счетчики команд устанавливаются на разные адреса cpu1.pc <= zero16; cpu2.pc <= zero16+256; cpu3.pc <= zero16+512; cpu1.cmd <= zero16; -- первое ядро стартует с NOP-ов cpu2.cmd <= stops; -- два других cpu3.cmd <= stops; -- остановлены elsif clk'event and clk = vcc and ena = vcc then -- кольцо из трех наборов регистров с одним логическим ядром cpu1 <= equinox_main(cpu3,di); cpu2 <= cpu1; cpu3 <= cpu2; end if; [/code]
На вход [b]ena[/b] в такой схеме уже можно смело подавать логическую единицу, и все три ядра заработают на частоте 1/3 от частоты [b]clk[/b]...
Собственно, в симуляторе это хорошо видно. Картинки не привожу, потому что кто сам с усам, тот их сам легко получит, а кому все это не интересно, тому и картинки не интересны.
|
|
|
|
Добавлено: Ср мар 14, 2012 19:28 |
|
|
|
|
|
Заголовок сообщения: |
Re: Конвейерный многоядерный процессор. |
|
|
Для ясности, о чем тут идет речь и чтобы собрать мысли в кучу (короче, чтобы навести тень на плетень), привожу здесь части кода процессора. Первое - это верхний файл процессора EQUINOX: Код: --- стандартные библиотеки --- LIBRARY IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_unsigned.all; --- свои библиотеки --- USE WORK.Common_lib.all; -- общая для всех USE WORK.EQUINOX_lib.all; -- библиотека для ядра процессора EQUINOX
-- объявляем одиночный процессор entity EQUINOX_SINGLE is Port( clk,reset,ena : in node := vcc; -- синхро и управляющие входы addr : out word; -- адрес памяти/устройств do : out word; -- выход данных, записываемых в память/устройства di : in word := zero16; -- вход данных/команд из памяти mwr,mrd : out node; -- управление работой памяти test_top,test_bot,test_pc,test_cmd : out word -- тестовые выходы ); end EQUINOX_SINGLE;
architecture rtl of EQUINOX_SINGLE is
signal cpu : cpu_t; -- все регистры процессора -- объявлены в одной переменной типа record, определенной в библиотеке
begin
-- главный процесс process (clk) begin if reset = gnd then -- по сбросу устанавливаем счетчик команд в ноль cpu1.pc <= zero16; -- и регистр команд заполняем командами NOP cpu.cmd <= nops; elsif clk'event and clk = vcc and ena = vcc then -- по каждому разрешенному такту -- выполняем один шаг работы процессора cpu <= equinox_main(cpu,di); -- зависящий от состояния -- процессора и входных данных -- функция определена в библиотеке ядра процессора end if; -- на этом vhdl-описание процессора закончено! -- осталось только подключить выходные сигналы addr <= equinox_main(cpu,di).oadr; do <= equinox_main(cpu,di).odat; mwr <= equinox_main(cpu,di).mwr; mrd <= equinox_main(cpu,di).mrd; end process; -- и подключить тестовые сигналы test_top <= cpu1.dst.top; test_bot <= cpu1.dst.bot; test_pc <= cpu1.pc; test_cmd <= cpu1.cmd; --- теперь совсем конец end; Описанный здесь однотактный процессор нормально работает, если в качестве памяти к нему подключить нечто быстрое, выдающее результат за один такт. Например, ПЗУ на логических ячейках, порты ввода/вывода, доп-регистры на ячейках ПЛИС, и получится простейший работоспособный контроллер. С рабочей частотой 100MHz и выше. Чтобы этот процессор заработал с внутренней памятью ПЛИС, его придется подтормаживать. Если на clk подать 100MHz, то на ena придется подать 33MHz со скважностью 1:3, и схема будет работать фактически на этих 33MHz... один такт работает логическое ядро процессора, два других - производится выборка из памяти.
Для ясности, о чем тут идет речь и чтобы собрать мысли в кучу (короче, чтобы навести тень на плетень), привожу здесь части кода процессора.
Первое - это верхний файл процессора EQUINOX:
[code] --- стандартные библиотеки --- LIBRARY IEEE; USE IEEE.std_logic_1164.all; USE IEEE.std_logic_unsigned.all; --- свои библиотеки --- USE WORK.Common_lib.all; -- общая для всех USE WORK.EQUINOX_lib.all; -- библиотека для ядра процессора EQUINOX
-- объявляем одиночный процессор entity EQUINOX_SINGLE is Port( clk,reset,ena : in node := vcc; -- синхро и управляющие входы addr : out word; -- адрес памяти/устройств do : out word; -- выход данных, записываемых в память/устройства di : in word := zero16; -- вход данных/команд из памяти mwr,mrd : out node; -- управление работой памяти test_top,test_bot,test_pc,test_cmd : out word -- тестовые выходы ); end EQUINOX_SINGLE;
architecture rtl of EQUINOX_SINGLE is
signal cpu : cpu_t; -- все регистры процессора -- объявлены в одной переменной типа record, определенной в библиотеке
begin
-- главный процесс process (clk) begin if reset = gnd then -- по сбросу устанавливаем счетчик команд в ноль cpu1.pc <= zero16; -- и регистр команд заполняем командами NOP cpu.cmd <= nops; elsif clk'event and clk = vcc and ena = vcc then -- по каждому разрешенному такту -- выполняем один шаг работы процессора cpu <= equinox_main(cpu,di); -- зависящий от состояния -- процессора и входных данных -- функция определена в библиотеке ядра процессора end if; -- на этом vhdl-описание процессора закончено! -- осталось только подключить выходные сигналы addr <= equinox_main(cpu,di).oadr; do <= equinox_main(cpu,di).odat; mwr <= equinox_main(cpu,di).mwr; mrd <= equinox_main(cpu,di).mrd; end process; -- и подключить тестовые сигналы test_top <= cpu1.dst.top; test_bot <= cpu1.dst.bot; test_pc <= cpu1.pc; test_cmd <= cpu1.cmd; --- теперь совсем конец end;[/code]
Описанный здесь однотактный процессор нормально работает, если в качестве памяти к нему подключить нечто быстрое, выдающее результат за один такт. Например, ПЗУ на логических ячейках, порты ввода/вывода, доп-регистры на ячейках ПЛИС, и получится простейший работоспособный контроллер. С рабочей частотой 100MHz и выше.
Чтобы этот процессор заработал с внутренней памятью ПЛИС, его придется подтормаживать. Если на [b]clk[/b] подать 100MHz, то на [b]ena[/b] придется подать 33MHz со скважностью 1:3, и схема будет работать фактически на этих 33MHz...
один такт работает логическое ядро процессора, два других - производится выборка из памяти.
|
|
|
|
Добавлено: Ср мар 14, 2012 19:13 |
|
|
|
|
|
Заголовок сообщения: |
Re: Конвейерный многоядерный процессор. |
|
|
Хищник писал(а): Но если такие частоты, то между триггерами явно должно быть минимум логики. Или сами операции конвейеризованы, и три отсюда ступени? конвейер в АЛУ возникает фактически из-за необходимости мультиплексирования результатов. А сами операции выполняются за один такт на отдельных схемах. фактически отдельно есть умножитель, сумматор-вычитатель, логик (and/or/xor/nand), инкрементер/декрементер/инвертор, вычислитель флага нуля и pc+1 в доп регистре вычисляется. Сейчас вспомнил, что надо еще чистый сдвигатель в процессор добавить, а то умножением его делать, как планировал, не кузяво. А дальше - мультиплексор результатов, которые надо во время выполнения команды положить в стеки/регистры. Вот этот мультиплексор и получился самый тормозной, когда схема не упирается в предел частоты встроенной памяти.
[quote="Хищник"] Но если такие частоты, то между триггерами явно должно быть минимум логики. Или сами операции конвейеризованы, и три отсюда ступени?[/quote]
конвейер в АЛУ возникает фактически из-за необходимости мультиплексирования результатов. А сами операции выполняются за один такт на отдельных схемах.
фактически отдельно есть умножитель, сумматор-вычитатель, логик (and/or/xor/nand), инкрементер/декрементер/инвертор, вычислитель флага нуля и pc+1 в доп регистре вычисляется. Сейчас вспомнил, что надо еще чистый сдвигатель в процессор добавить, а то умножением его делать, как планировал, не кузяво.
А дальше - мультиплексор результатов, которые надо во время выполнения команды положить в стеки/регистры. Вот этот мультиплексор и получился самый тормозной, когда схема не упирается в предел частоты встроенной памяти.
|
|
|
|
Добавлено: Ср мар 14, 2012 04:30 |
|
|
|
|
|
Заголовок сообщения: |
Re: Конвейерный многоядерный процессор. |
|
|
WingLion писал(а): в один не уложилось.. в АЛУ три ступени выполнения. А операций почти два десятка. Но если такие частоты, то между триггерами явно должно быть минимум логики. Или сами операции конвейеризованы, и три отсюда ступени?
[quote="WingLion"]в один не уложилось.. в АЛУ три ступени выполнения. А операций почти два десятка.[/quote] Но если такие частоты, то между триггерами явно должно быть минимум логики. Или сами операции конвейеризованы, и три отсюда ступени?
|
|
|
|
Добавлено: Вт мар 13, 2012 23:06 |
|
|
|
|
|
Заголовок сообщения: |
Re: Конвейерный многоядерный процессор. |
|
|
Хищник писал(а): Так оно в один logic level уложилось? А сколько команд в АЛУ? в один не уложилось.. в АЛУ три ступени выполнения. А операций почти два десятка.
[quote="Хищник"]Так оно в один logic level уложилось? А сколько команд в АЛУ?[/quote]
в один не уложилось.. в АЛУ три ступени выполнения. А операций почти два десятка.
|
|
|
|
Добавлено: Вт мар 13, 2012 22:16 |
|
|
|
|
|
Заголовок сообщения: |
Re: Конвейерный многоядерный процессор. |
|
|
Так оно в один logic level уложилось? А сколько команд в АЛУ?
Так оно в один logic level уложилось? А сколько команд в АЛУ?
|
|
|
|
Добавлено: Вт мар 13, 2012 21:38 |
|
|
|
|
|
Заголовок сообщения: |
Re: Конвеерный многоядерный процессор. |
|
|
Сегодня высказанная выше идея прошла практическую проверку. За основу взял свой четырехбитный EQUINOX, раскидал его логику на конвейер, подключил тестовую память и прогнал маленькую тестовую программку с симуляторе, запуская одно из шести ядер. Логику раскидывал наобум, проверяя предельную частоту, на которую разводился процессор и подглядывая, какая цепь дает наибольшую задержку. В результате ALU "рассыпалось" на три стадии, которые на конвейере без проблем отрабатываются на предельной частоте. Результаты для 6Е16 получились такие: Объем шестиядерного процессора - ~3000LCELLs Частота на циклоне-3 с максимальным спидгрейдом - 250MHz. на циклоне-3 со спидгрейдом 8 частота - 200-210 MHz. на циклоне-2 со спидгрейдом 7 частота - 200MHz. Для интереса посмотрел, что получается на 3-м стратиксе... - более 500MHz... Все варианты с включенным в систему команд умножением 16x16.
Сегодня высказанная выше идея прошла практическую проверку.
За основу взял свой четырехбитный [url=http://winglion.ru/equinox/]EQUINOX[/url], раскидал его логику на конвейер, подключил тестовую память и прогнал маленькую тестовую программку с симуляторе, запуская одно из шести ядер.
Логику раскидывал наобум, проверяя предельную частоту, на которую разводился процессор и подглядывая, какая цепь дает наибольшую задержку. В результате ALU "рассыпалось" на три стадии, которые на конвейере без проблем отрабатываются на предельной частоте.
Результаты для 6Е16 получились такие:
Объем шестиядерного процессора - ~3000LCELLs Частота на циклоне-3 с максимальным спидгрейдом - 250MHz. на циклоне-3 со спидгрейдом 8 частота - 200-210 MHz. на циклоне-2 со спидгрейдом 7 частота - 200MHz.
Для интереса посмотрел, что получается на 3-м стратиксе... :shock: - более 500MHz...
Все варианты с включенным в систему команд умножением 16x16.
|
|
|
|
Добавлено: Вт мар 13, 2012 18:30 |
|
|
|
|
|
Заголовок сообщения: |
Конвейерный многоядерный процессор. |
|
|
При разработке процессоров на ПЛИС фирмы ALTERA возникает ряд сложностей, связанный с особенностями встроенной блоковой памяти. Память может работать на высокой частоте, но время выборки составляет несколько тактов, в результате чего при последовательной выборке команд и данных возникают лишние задержки.
На форуме уже высказывалась идея, как их обойти. Для этого можно использовать многоядерный процессор, разделение времени для ядер которого происходит потактово, и тогда каждый такт память работает с одним ядром, а следующий и предыдущий с другим. Такое построение позволяет задействовать скорость памяти полностью практически без потерь на ожидание.
В то же время, скорость процессора так же зависит от разложения его действий по ступеням конвейера, в связи с чем возникла идея объединения конвейерной работы процессора с конвейерной работой памяти.
Запишем работу блочной памяти ПЛИС (здесь и далее речь и блочной памяти ПЛИС ф. ALTERA) в виде следующих действий:
1. фиксация адреса. 2. Выборка данных из массива и фиксация их в выходном регистре.
Фактически, это те два такта, требуемые для выборки данных из блочной памяти ПЛИС. Реально, для увеличения скорости работы памяти, приходится добавлять на выход еще один регистр, и тогда добавляется этап:
3. Фиксация выходных данных в дополнительном регистре.
Теперь таким же образом запишем работу процессора с конвейером. Для простоты будем считать, что этапов конвейера всего два:
1. Фиксация команды в регистре команд 2. Дешифрация и исполнение команды - модификация "всех" регистров процессора.
В случае, когда и память и процессор успевает сделать все что нужно, оба этапа объединяются в один, и получается процессор с однотактовой схемой.
однако, память у нас не успевает, и процессор не редко подтормаживает на сложных командах поэтому дйствия разносим, а исполнение команды расширяем еще на один такт.
Объединяя обе схемы получаем следующую последовательность действий, которую должна выполнять система процессор-память:
1. фиксация адреса. 2. Выборка данных из массива и фиксация их в выходном регистре. 3. Фиксация выходных данных в дополнительном регистре. 4. Фиксация команды в регистре команд 5. Дешифрация и исполнение команды - модификация "всех" регистров процессора. 6. Дополнительный период для исполнения команды
Эта последовательность в простейшем случае должна исполняться по кругу. При этом на исполнения одной команды процессора тратится шесть тактов.
Можно искать возможность оптимизации, сокращения этого круга для повышения общей скорости системы, но в данном случае этого не требуется, потому что идея данного поста, как раз и заключается в том, как получить максимум скорости от такой схемы без применения особых ухищрений.
Идея в следующем. Состояние процессора определяется содержимым его регистров, и может быть помещено в некий регистр конечной длины. Возьмем 6 таких регистров, поместим в них начальные данные для шести процессоров и зациклим регистры в кольцо так, что бы каждый такт содержимое регистров сдвигалось по кругу. Закрепим за каждой позицией в круге одно из действий описанных выше, и получим в результате кольцевой шестипозиционный конвейер, который при исполнении будет за шесть тактов выполнять шесть потоков команд для шести процессоров.
Общая скорость исполнения для такой системы соответствует тактовой частоте. И на каждый процесс отводится ровно 1/6 общего времени без потерь на переключение процессов.
Так же стоит заметить, что главная проблема конвейера - необходимость сброса при переходах в данном случае отпадает, потому что необходимость в таком сбросе просто отсутствует. Каждая команда проходит полный цикл конвейера и исполняется фактически без задержек.
При разработке процессоров на ПЛИС фирмы ALTERA возникает ряд сложностей, связанный с особенностями встроенной блоковой памяти. Память может работать на высокой частоте, но время выборки составляет несколько тактов, в результате чего при последовательной выборке команд и данных возникают лишние задержки.
На форуме уже высказывалась идея, как их обойти. Для этого можно использовать многоядерный процессор, разделение времени для ядер которого происходит потактово, и тогда каждый такт память работает с одним ядром, а следующий и предыдущий с другим. Такое построение позволяет задействовать скорость памяти полностью практически без потерь на ожидание.
В то же время, скорость процессора так же зависит от разложения его действий по ступеням конвейера, в связи с чем возникла идея объединения конвейерной работы процессора с конвейерной работой памяти.
Запишем работу блочной памяти ПЛИС (здесь и далее речь и блочной памяти ПЛИС ф. ALTERA) в виде следующих действий:
1. фиксация адреса. 2. Выборка данных из массива и фиксация их в выходном регистре.
Фактически, это те два такта, требуемые для выборки данных из блочной памяти ПЛИС. Реально, для увеличения скорости работы памяти, приходится добавлять на выход еще один регистр, и тогда добавляется этап:
3. Фиксация выходных данных в дополнительном регистре.
Теперь таким же образом запишем работу процессора с конвейером. Для простоты будем считать, что этапов конвейера всего два:
1. Фиксация команды в регистре команд 2. Дешифрация и исполнение команды - модификация "всех" регистров процессора.
В случае, когда и память и процессор успевает сделать все что нужно, оба этапа объединяются в один, и получается процессор с однотактовой схемой.
однако, память у нас не успевает, и процессор не редко подтормаживает на сложных командах поэтому дйствия разносим, а исполнение команды расширяем еще на один такт.
Объединяя обе схемы получаем следующую последовательность действий, которую должна выполнять система процессор-память:
1. фиксация адреса. 2. Выборка данных из массива и фиксация их в выходном регистре. 3. Фиксация выходных данных в дополнительном регистре. 4. Фиксация команды в регистре команд 5. Дешифрация и исполнение команды - модификация "всех" регистров процессора. 6. Дополнительный период для исполнения команды
Эта последовательность в простейшем случае должна исполняться по кругу. При этом на исполнения одной команды процессора тратится шесть тактов.
Можно искать возможность оптимизации, сокращения этого круга для повышения общей скорости системы, но в данном случае этого не требуется, потому что идея данного поста, как раз и заключается в том, как получить максимум скорости от такой схемы без применения особых ухищрений.
Идея в следующем. Состояние процессора определяется содержимым его регистров, и может быть помещено в некий регистр конечной длины. Возьмем 6 таких регистров, поместим в них начальные данные для шести процессоров и зациклим регистры в кольцо так, что бы каждый такт содержимое регистров сдвигалось по кругу. Закрепим за каждой позицией в круге одно из действий описанных выше, и получим в результате кольцевой шестипозиционный конвейер, который при исполнении будет за шесть тактов выполнять шесть потоков команд для шести процессоров.
Общая скорость исполнения для такой системы соответствует тактовой частоте. И на каждый процесс отводится ровно 1/6 общего времени без потерь на переключение процессов.
Так же стоит заметить, что главная проблема конвейера - необходимость сброса при переходах в данном случае отпадает, потому что необходимость в таком сбросе просто отсутствует. Каждая команда проходит полный цикл конвейера и исполняется фактически без задержек.
|
|
|
|
Добавлено: Пн мар 12, 2012 19:34 |
|
|
|
|