Лабораторная работа №7 "Тракт данных"
Микроархитектуру можно разделить на две части: тракт данных и устройство управления. По тракту данных перемещаются данные (из памяти инструкций, регистрового файла, АЛУ, памяти данных, мультиплексоров), а устройство управления (в нашем случае — декодер инструкций) получает текущую инструкцию из тракта и в ответ говорит ему как именно её выполнить, то есть управляет тем, как эти данные будут через проходить тракт данных.
Цель
Описать на языке SystemVerilog процессор с архитектурой RISC-V, реализовав его тракт данных, используя разработанные ранее блоки, и подключив к нему устройство управления. Итогом текущей лабораторной работы станет процессор RISC-V, который пока что сможет работать с памятью данных лишь посредством 32-битных слов (то есть БЕЗ инструкций, связанных с байтами и полусловами: lh
, lhu
, lb
, lbu
, sh
, sb
).
Ход работы
- Изучить микроархитектурную реализацию однотактного процессора RISC-V (без поддержки команд загрузки/сохранения байт/полуслов)
- Реализовать тракт данных с подключенным к нему устройством управления(#задание)
- Подготовить программу по индивидуальному заданию и загрузить ее в память инструкций
- Сравнить результат работы процессора на модели в Vivado и в симуляторе программы ассемблера
Микроархитектура RISC-V
processor_core
Рассмотрим микроархитектуру процессорного ядра processor_core
. Данный модуль обладает следующим прототипом и микроархитектурой:
module processor_core (
input logic clk_i,
input logic rst_i,
input logic stall_i,
input logic [31:0] instr_i,
input logic [31:0] mem_rd_i,
output logic [31:0] instr_addr_o,
output logic [31:0] mem_addr_o,
output logic [ 2:0] mem_size_o,
output logic mem_req_o,
output logic mem_we_o,
output logic [31:0] mem_wd_o
);
endmodule
Рисунок 1. Микроархитектура ядра процессора RISC-V.
Предложенная микроархитектура имеет схожую структуру c процессором CYBERcobra 3000 Pro 2.0
из ЛР№4, с некоторыми изменениями.
В первую очередь изменились входы и выходы процессора:
- память инструкций вынесена наружу процессора, таким образом, у процессора появляются входы и выходы:
instr_addr_o
иinstr_i
; - помимо прочего, у модуля появились сигналы интерфейса памяти данных, реализованной в ЛР№6:
mem_addr_o
— адрес внешней памяти;mem_req_o
— запрос на обращение во внешнюю память;mem_size_o
— размер данных при обращении в память;mem_we_o
— сигнал разрешения записи во внешнюю память;mem_wd_o
— данные для записи во внешнюю память;mem_rd_i
— считанные из внешней памяти данные; Эти сигналы используются при выполнении инструкций загрузки (сохранения) информации из (в) памяти данных.
- еще у процессора появился вход
stall_i
, приостанавливающий обновление программного счётчика.
Кроме того, в данной микроархитектуре используется пять различных видов констант (соответствующих определенным типам инструкций).
Константы I
, U
, S
используются для вычисления адресов и значений. Поэтому все эти константы должны быть подключены к АЛУ. А значит теперь, для выбора значения для операндов требуются мультиплексоры, определяющие, что именно будет подаваться на АЛУ.
Обратите внимание на константу imm_U
. В отличие от всех остальных констант, она не знакорасширяется, вместо этого к ней "приклеивается" справа 12 нулевых бит.
Константы B
и J
используются для условного и безусловного перехода (в киберкобре для этого использовалась одна константа offset
).
Программный счётчик (PC
) теперь также изменяется более сложным образом. Поскольку появился еще один вид безусловного перехода (jalr
), программный счётчик может не просто увеличиться на значение константы из инструкции, но и получить совершенно новое значение в виде суммы константы и значения из регистрового файла (см. на самый левый мультиплексор рис. 1). Обратите внимание, что младший бит этой суммы должен быть обнулен — таково требование спецификации [1, стр. 28].
Поскольку обращение во внешнюю память требует времени, необходимо приостанавливать программный счётчик, чтобы до конца обращения в память не начались исполняться последующие инструкции. Для этого у программного счётчика появился управляющий сигнал stall_i
. Программный счётчик может меняться только когда этот сигнал равен нулю (иными словами, инверсия этого сигнала является сигналом enable
для регистра PC
).
processor_system
После реализации процессорного ядра, к нему необходимо подключить память. Это происходит в модуле processor_system
.
module processor_system(
input logic clk_i,
input logic rst_i
);
endmodule
Рисунок 2. Микроархитектура процессорной системы.
Обратите внимание на регистр stall
. Этот регистр и будет управлять разрешением на запись в программный счётчик PC
. Поскольку мы используем блочную память, расположенную прямо в ПЛИС, доступ к ней осуществляется за 1 такт, а значит, что при обращении в память, нам необходимо "отключить" программный счётчик ровно на 1 такт. Если бы использовалась действительно "внешняя" память (например чип DDR3), то вместо этого регистра появилась бы другая логика, выставляющая на вход ядра stall_i
единицу пока идет обращение в память.
Задание
Реализовать ядро процессора processor_core
архитектуры RISC-V по предложенной микроархитектуре. Подключить к нему память инструкций и память данных в модуле processor_system
. Проверить работу процессора с помощью программы, написанной на ассемблере RISC-V по индивидуальному заданию, которое использовалось для написания программы для процессора архитектуры CYBERcobra.
Напишем простую программу, которая использует все типы инструкций для проверки нашего процессора. Сначала напишем программу на ассемблере:
00: addi x1, x0, 0x75С
04: addi x2, x0, 0x8A7
08: add x3, x1, x2
0C: and x4, x1, x2
10: sub x5, x4, x3
14: mul x6, x3, x4 // неподдерживаемая инструкция
18: jal x15, 0x00050 // прыжок на адрес 0x68
1C: jalr x15, 0x0(x6)
20: slli x7, x5, 31
24: srai x8, x7, 1
28: srli x9, x8, 29
2C: lui x10, 0xfadec
30: addi x10, x10,-1346
34: sw x10, 0x0(x4)
38: sh x10, 0x6(x4)
3C: sb x10, 0xb(x4)
40: lw x11, 0x0(x4)
44: lh x12, 0x0(x4)
48: lb x13, 0x0(x4)
4С: lhu x14, 0x0(x4)
50: lbu x15, 0x0(x4)
54: auipc x16, 0x00004
58: bne x3, x4, 0x08 // перескок через
5С: // нелегальную нулевую инструкцию
60: jal x17, 0x00004
64: jalr x14, 0x0(x17)
68: jalr x18, 0x4(x15)
Листинг 1. Пример программы на ассемблере.
Теперь в соответствии с кодировкой инструкций переведем программу в машинные коды:
00: 011101011100 00000 000 00001 0010011 (0x75C00093)
04: 100010100111 00000 000 00010 0010011 (0x8A700113)
08: 0000000 00010 00001 000 00011 0110011 (0x002081B3)
0C: 0000000 00010 00001 111 00100 0110011 (0x0020F233)
10: 0100000 00011 00100 000 00101 0110011 (0x403202B3)
14: 0000001 00100 00011 000 00110 0110011 (0x02418333)
18: 00000101000000000000 01111 1101111 (0x050007EF)
1C: 000000000000 00110 000 01111 1100111 (0x000307E7)
20: 0000000 11111 00101 001 00111 0010011 (0x01F29393)
24: 0100000 00001 00111 101 01000 0010011 (0x4013D413)
28: 0000000 11101 01000 101 01001 0010011 (0x01D45493)
2C: 11111010110111101100 01010 0110111 (0xFADEC537)
30: 101010111110 01010 000 01010 0010011 (0xABE50513)
34: 0000000 01010 00100 010 00000 0100011 (0x00A22023)
38: 0000000 01010 00100 001 00110 0100011 (0x00A21323)
3C: 0000000 01010 00100 000 01011 0100011 (0x00A205A3)
40: 000000000000 00100 010 01011 0000011 (0x00022583)
44: 000000000000 00100 001 01100 0000011 (0x00021603)
48: 000000000000 00100 000 01101 0000011 (0x00020683)
4C: 000000000000 00100 101 01110 0000011 (0x00025703)
50: 000000000000 00100 100 01111 0000011 (0x00024783)
54: 00000000000000000100 10000 0010111 (0x00004817)
58: 0000000 00011 00100 001 01000 1100011 (0x00321463)
5C: 00000000 00000000 00000000 00000000 (0x00000000)
60: 00000000010000000000 10001 1101111 (0x004008EF)
64: 000000000000 10001 000 01110 1100111 (0x00088767)
68: 000000000100 01111 000 10010 1100111 (0x00478967)
Листинг 2. Программа из Листинга 1, представленная в машинных кодах.
Данная программа, представленная в шестнадцатеричном формате находится в файле program.mem.
Порядок выполнения задания
- Внимательно ознакомьтесь микроархитектурной реализацией процессорного ядра. В случае возникновения вопросов, проконсультируйтесь с преподавателем.
- Замените файл
program.mem
вDesign Sources
проекта новым файлом program.mem, приложенном в данной лабораторной работе. Данный файл содержит программу из листинга 1. - Опишите модуль процессорного ядра с таким же именем и портами, как указано в задании.
- Процесс реализации модуля очень похож на процесс описания модуля cybercobra, однако теперь появляется:
- декодер
- дополнительные мультиплексоры и знакорасширители.
- Сперва рекомендуется создать все провода, которые будут подключены к входам и выходам каждого модуля на схеме.
- Затем необходимо создать экземпляры модулей.
- Также необходимо создать 32-разрядные константы I, U, S, B и J-типа и программный счётчик.
- После необходимо описать логику, управляющую созданными в п. 3.2 проводами.
- В конце останется описать логику работы программного счётчика.
- Процесс реализации модуля очень похож на процесс описания модуля cybercobra, однако теперь появляется:
- Опишите модуль процессорной системы, объединяющий ядро процессора (
processor_core
) с памятями инструкция и данных.- Опишите модуль с таким же именем и портами, как указано в задании.
- При создании объекта модуля
processor_core
в модулеprocessor_system
вы должны использовать имя сущностиcore
(т.е. создать объект в виде:processor_core core(...
).
- Проверьте модуль с помощью верификационного окружения, представленного в файле
lab_07.tb_processor_system.sv
.- Перед запуском симуляции убедитесь, что выбран правильный модуль верхнего уровня в
Simulation Sources
. - Как и в случае с проверкой процессора архитектуры CYBERcobra, вам не будет сказано пройден тест или нет. Вам необходимо самостоятельно, такт за тактом проверить что процессор правильно выполняет описанные в Листинге 1 инструкции (см. порядок выполнения задания ЛР№4). Для этого, необходимо сперва самостоятельно рассчитать что именно должна сделать данная инструкция, а потом проверить что процессор сделал именно это.
- Перед запуском симуляции убедитесь, что выбран правильный модуль верхнего уровня в
- Проверьте работоспособность вашей цифровой схемы в ПЛИС.
Прочти меня, когда выполнишь.
Поздравляю, ты сделал(а) свой первый взрослый процессор! Теперь ты можешь говорить:Я способен(на) на всё! Я сам(а) полностью, с нуля, сделал(а) процессор с архитектурой RISC-V! Что? Не знаешь, что такое архитектура? Пф, щегол! Подрастешь – узнаешь