Конвейеризированное процессорное ядро
Несложно заметить, что предложенную микроархитектуру многотактного процессора (рис.7.1) можно относительно просто превратить в конвейеризированную. Для этого достаточно (вот сейчас будет страшно - а точно ли?) разрешить работу всех промежуточных регистров Rx, а также блоков программного счетчика, файл-регистра, регистров специальных функций, и памяти на запись.
Первым вариантом модификации будет исключение из микроархитектуры кольцевого сдвигового регистра, подача входы разрешения работы модулей с памятью логической единицы ("разрешено").
При таком варианте в случае линейного кода на каждом такте значение программного счетчика будет инкрементироваться и выбираться новые инструкции программы - рис.7.2.
Смотря на рис.7.2 можно с одной стороны порадоваться - выборка инструкций действительно конвейеризовалась, но вот выполнение последовательности команд наталкивается на неопределенность при выборке операндов из файл-регистра.
Последующий разбор показывает, что в текущем варианте разбиения конвейера по этапам может нарушаться ( и для тестового программного кода нарушается) временнАя последовательность выполнения команд - выборка операнда последующей команды начинается раньше, чем производится запись результата предыдущей.
Следовательно, необходимо немного пересмотреть вариант разбиения конвейера по этапам для корректной работы.
Микроархитектурные блоки процессора оставляем пока как и были:
rv_pc - программный счетчик;
rv_mem - блок памяти (программная и оперативная;
rv_desh - дешифратор команд (слова-инструкции);
rv_imm - формирователь непосредственного значения из слова-инструкции;
rv_reg_file - файл-регистр
rv_ops_mux - коммутатор операндов для АЛУ;
rv_cmp - формирователь сигнала разрешения перехода;
rv_alu_v - АЛУ;
rv_rez_mux - коммутатор результатов;
rv_csr - блок регистров специального назначения.
Новый вариант разбиения по этапам:
L0 - выборка текущего значения программного счетчика (точнее пары значений - PC и РС+4).
L1 - выборка слова-инструкции из памяти.
L2 - дешифрация инструкции - выделение адресов операндов, типа инструкции, формирование управляющих сигналов.
L3 - вычисления - выборка операндов из файл-регистров, работа АЛУ, чтение/запись данных из оперативной памяти, запись данных в файл-регистры.
L4 - запись нового значения в программный счётчик.
Пробуем рассмотреть возможные сигналы и действия на каждом из этапов. Промежуточные результаты каждого из этапов по прежнему фиксируются в неархитектурных "буферных" регистрах, ожидаемо их стало меньше (R0 - R4), и разрядность их также можно уменьшить. Ряд сигналов, аналогично предыдущей версии, "пробрасываются" по этапам (напрямую между регистрами) в том случае, если они не задействованы в них. Работа блоков с элементами памяти и промежуточных регистров разрешена всё время.
Структурная схема конвейеризированного варианта процессора представлена на рис.7.4.
Этапы L0-L2 остаются пока без изменений.
L0 - выборка текущего значения программного счетчика
Текущее значение программного счетчика и его инкремента (PC+4) запоминаются в регистре R1. Выходными линиями, соответствующими PC, адресуется память (память программ). Также пара PC, PC+4 с выхода R1 будет подана на вход регистра R2.
L1 - выборка слова-инструкции из памяти
В регистре R2 фиксируется слово инструкции из памяти и текущие значения пары PC, PC+4. Выход регистра подается на декодер инструкции и на схемы формирования непосредственного значения (immediate). Значения счетчиков передаются на вход следующего регистра (R3).
wire [31:0]l0r1_PC;
wire [31:0]l0r1_PCplus;
wire [31:0]r1l1_PC;
wire [31:0]r1l1_PCplus;
rv_pc pc( // programm counter
.clk(clk),
.rst_n(rst),
.pc_load(r6l7_PC_load),
.pc_next(l6r7_Rez),
.pc(l0r1_PC),
.pc_plus(l0r1_PCplus)
);
wire [255:0] r1_in;
assign r1_in = {l0r1_PC, l0r1_PCplus, 192'h0};
wire [255:0] r1_out;
assign r1_out = {r1l1_PC, r1l1_PCplus, 192'h0};
rv_r_reg R1(
.clk(clk),
.rst_n(rst),
.en(en_level[0]),
.r_in(r1_in),
.r_out(r1_out)
);
|
wire [31:0] l1r2_iw;
wire [31:0] l1r2_PC;
wire [31:0] l1r2_PCplus;
rv_mem mem( // system memory
.clk(clk),
.i_addr(r1l1_PC),
.code_out(l1r2_iw),
.d_addr(r5l5_Rez),
.d_out(l5r6_Mem_data),
.d_in(r5l5_Rs2_reg),
.we(r5l5_mem_wr)
);
// L1_R2
wire [31:0]r2l2_iw;
wire [31:0]r2l2_PC;
wire [31:0]r2l2_PCplus;
wire [255:0] r2_in;
wire [255:0] r2_out;
assign r2_in = {l1r2_iw, r1l1_PC, r1l1_PCplus, 160'h0};
assign r2_out = {r2l2_iw, r2l2_PC, r2l2_PCplus, 160'h0};
rv_r_reg R2(
.clk(clk),
.rst_n(rst),
.en(en_level[1]),
.r_in(r2_in),
.r_out(r2_out)
);
|
L2 - дешифрация инструкции
Из слова-инструкции идет выделение адресов регистров-операндов, типа (опкодов и функциональных полей) инструкции, формирование управляющих сигналов на запись в файл-регистры (регистров общего назначения и специальных регистров).





