ЛР13. Обновление тб и порядка выполнения задания

This commit is contained in:
Andrei Solodovnikov
2024-07-28 12:00:35 +03:00
parent ee071a541c
commit 124b37c1a4
4 changed files with 164 additions and 137 deletions

View File

@@ -154,31 +154,37 @@ _Рисунок 2. Карта памяти периферийных устрой
1. Внимательно ознакомьтесь с [примером описания модуля контроллера](../../Basic%20Verilog%20structures/Controllers.md).
2. Внимательно ознакомьтесь со спецификацией контроллеров периферии своего варианта. В случае возникновения вопросов, проконсультируйтесь с преподавателем.
3. Реализуйте модули контроллеров периферии. Имена модулей и их порты будут указаны в [описании контроллеров](#описание-контроллеров-периферийных-устройств). Пример разработки контроллера приведен в [примере описания модуля контроллера](../../Basic%20Verilog%20structures/Controllers.md).
3. Добавьте в проект пакет [`peripheral_pkg`](peripheral_pkg.sv). Данный пакет содержит старшие части адресов периферии в виде параметров, а также вспомогательные вызовы, используемые тестбенчем.
4. Реализуйте модули контроллеров периферии. Имена модулей и их порты будут указаны в [описании контроллеров](#описание-контроллеров-периферийных-устройств). Пример разработки контроллера приведен в [примере описания модуля контроллера](../../Basic%20Verilog%20structures/Controllers.md).
1. Готовые модули периферии, управление которыми должны осуществлять модули-контроллеры хранятся в папке `peripheral modules`.
4. Обновите модуль `riscv_unit` в соответствии с разделом ["Дополнительные правки модуля riscv_unit"](#дополнительные-правки-модуля-riscv_unit).
5. Обновите модуль `riscv_unit` в соответствии с разделом ["Дополнительные правки модуля riscv_unit"](#дополнительные-правки-модуля-riscv_unit).
1. Подключите в проект файл `sys_clk_rst_gen.sv`.
2. Добавьте в модуль `riscv_unit` входы и выходы периферии, а так же замените вход `rst_i` входом `resetn_i`. **Необходимо добавить порты даже тех периферийных устройств, которые вы не будете реализовывать**.
3. Создайте в начале описания модуля `riscv_unit` экземпляр модуля `sys_clk_rst_gen`, скопировав приведенный фрагмент кода.
4. Замените подключение тактового сигнала исходных подмодулей `riscv_unit` на появившийся сигнал `sysclk`. Убедитесь, что на модули, имеющие сигнал сброса, приходит сигнал `rst`.
5. Интегрируйте модули контроллеров периферии в процессорную систему по приведенной схеме руководствуясь старшими адресами контроллеров, представленными на карте памяти ([_рис. 2_](../../.pic/Labs/lab_13_periph/fig_02.png)). Это означает, что если вы реализуете контроллер светодиодов, на его вход `req_i` должна подаваться единица в случае, если `mem_req_o == 1` и старшие 8 бит адреса равны `0x02`.
6. Интегрируйте модули контроллеров периферии в процессорную систему по приведенной схеме руководствуясь старшими адресами контроллеров, представленными на карте памяти ([_рис. 2_](../../.pic/Labs/lab_13_periph/fig_02.png)). Это означает, что если вы реализуете контроллер светодиодов, на его вход `req_i` должна подаваться единица в случае, если `mem_req_o == 1` и старшие 8 бит адреса равны `0x02`.
1. При интеграции вы должны подключить только модули-контроллеры вашего варианта. Контроллеры периферии других вариантов подключать не надо.
2. Во время интеграции, вы должны использовать старшую часть адреса, представленную в карте памяти для формирования сигнала `req_i` для ваших модулей-контроллеров.
6. Проверьте работу процессорной системы с помощью моделирования.
1. Для каждой пары контроллеров в папке `firmware/mem_files` представлены файлы, инициализирующие память инструкций. Обратите внимание, что для пары "PS2-VGA" также необходим файл, инициализирующий память данных (в модуле `data_mem` необходимо добавить вызов инициализирующей функции `$readmemh` в блоке `initial`).
2. Для проверки тестбенч имитирует генерацию данных периферийных устройств ввода. Перед проверкой желательно найти в тестбенче `initial`-блок своего устройства ввода (`sw_block`, `ps2_block`, `uart_block`) — по этому блоку будет понятно, какие данные будет передавать устройство ввода. Именно эти данные в итоге должны оказаться на шине `mem_rd_i`.
3. Для того, чтобы понять, что устройство работает должным образом, в первую очередь необходимо убедиться, что контроллер устройства ввода успешно осуществил прием данных (сгенерированные тестбенчем данные оказались в соответствующем регистре контроллера периферийного устройства) и выполнил запрос на прерывание.
4. После чего, необходимо убедиться, что процессор среагировал на данное прерывание, и в процессе его обработки в контроллер устройства вывода были поданы выходные данные.
5. Для того, чтобы лучше понимать как именно процессор будет обрабатывать прерывание, рекомендуется ознакомиться с исходным кодом исполняемой программы, расположенным в папке `firmware/software`.
7. Проверьте работу процессорной системы с помощью моделирования.
1. Для моделирования используйте тестбенч `lab_13_tb_system`.
2. Для каждой пары контроллеров в папке `firmware/mem_files` представлены файлы, инициализирующие память инструкций. Обратите внимание, что для пары "PS2-VGA" также необходим файл, инициализирующий память данных (в модуле `data_mem` необходимо добавить вызов инициализирующей функции `$readmemh` в блоке `initial`).
3. Для проверки тестбенч имитирует генерацию данных периферийных устройств ввода. Перед проверкой желательно найти в тестбенче `initial`-блок своего устройства ввода (`sw_block`, `ps2_block`, `uart_block`) — по этому блоку будет понятно, какие данные будет передавать устройство ввода. Именно эти данные в итоге должны оказаться на шине `mem_rd_i`.
4. Для того, чтобы понять, что устройство работает должным образом, в первую очередь необходимо убедиться, что контроллер устройства ввода успешно осуществил прием данных (сгенерированные тестбенчем данные оказались в соответствующем регистре контроллера периферийного устройства) и выполнил запрос на прерывание.
5. После чего, необходимо убедиться, что процессор среагировал на данное прерывание, и в процессе его обработки в контроллер устройства вывода были поданы выходные данные.
6. Для того, чтобы лучше понимать как именно процессор будет обрабатывать прерывание, рекомендуется ознакомиться с исходным кодом исполняемой программы, расположенным в папке `firmware/software`.
1. Общая логика программ для всех периферий сводится к ожиданию в бесконечном цикле прерывания от устройства ввода, после чего в процессе обработки прерывания процессор загружает данные от устройства ввода и (возможно преобразовав их) выдает их на устройство вывода.
2. В случае правильной работы программы на временной диаграмме это будет отображено следующим образом: сразу после поступления прерывания от устройства ввода, на системной шине начинается операция чтения из устройства ввода (это легко определить по старшей части адреса, к которому обращается процессор), после чего выполняются операции записи в устройство вывода (аналогично, обращение к устройству вывода можно определить по адресу, к которому обращается процессор).
6. При моделировании светодиодов лучше уменьшить значение, до которого считает счетчик в режиме "моргания" в 1000 раз, чтобы сократить время моделирования до очередного переключения светодиодов. Перед генерацией битстрима это значение будет необходимо восстановить, иначе моргание станет слишком быстрым и его нельзя будет воспринять невооруженным взглядом.
7. При моделировании светодиодов лучше уменьшить значение, до которого считает счетчик в режиме "моргания" в 1000 раз, чтобы сократить время моделирования до очередного переключения светодиодов. Перед генерацией битстрима это значение будет необходимо восстановить, иначе моргание станет слишком быстрым и его нельзя будет воспринять невооруженным взглядом.
7. Переходить к следующему пункту можно только после того, как вы полностью убедились в работоспособности модуля на этапе моделирования (увидели корректные значения на выходных сигналах периферии, либо (если по сигналам периферии сложно судить о работоспособности), значениям в контрольных/статусных регистрах модуля-контроллера этой периферии). Генерация битстрима будет занимать у вас долгое время, а итогом вы получите результат: заработало / не заработало, без какой-либо дополнительной информации, поэтому без прочного фундамента на моделировании далеко уехать у вас не выйдет.
8. Переходить к следующему пункту можно только после того, как вы полностью убедились в работоспособности модуля на этапе моделирования (увидели корректные значения на выходных сигналах периферии, либо (если по сигналам периферии сложно судить о работоспособности), значениям в контрольных/статусных регистрах модуля-контроллера этой периферии). Генерация битстрима будет занимать у вас долгое время, а итогом вы получите результат: заработало / не заработало, без какой-либо дополнительной информации, поэтому без прочного фундамента на моделировании далеко уехать у вас не выйдет.
<!-- 1. Для каждой пары контроллеров периферии предложено две программы: с обновлением данных по опросу и по прерываниям. Запустите моделирование сначала для одной программы, затем для другой (для этого необходимо обновить файл, инициализирующий память инструкций). После проверки работоспособности процессора, сравните поведение сигналов LSU для этих программ. -->
8. Подключите к проекту файл ограничений ([nexys_a7_100t.xdc](nexys_a7_100t.xdc)), если тот еще не был подключен, либо замените его содержимое данными из файла к этой лабораторной работе.
9. Проверьте работу вашей процессорной системы на отладочном стенде с ПЛИС.
9. Подключите к проекту файл ограничений ([nexys_a7_100t.xdc](nexys_a7_100t.xdc)), если тот еще не был подключен, либо замените его содержимое данными из файла к этой лабораторной работе.
10. Проверьте работу вашей процессорной системы на отладочном стенде с ПЛИС.
1. Обратите внимание, что в данной лабораторной уже не будет модуля верхнего уровня `nexys_...`, так как ваш модуль процессорной системы уже полностью самостоятелен и взаимодействует непосредственно с ножками ПЛИС через модули, управляемые контроллерами периферии.
2. Для проверки периферии переключателей и светодиодов будет достаточно одного лишь отладочного стенда. Для проверки всей остальной периферии может могут потребоваться: компьютер (для uart_rx / uart_tx), клавиатура (для контролера клавиатуры) и VGA-монитор для VGA-контроллера.
1. Чтобы проверить работоспособность контроллеров UART, необходимо запустить на компьютере программу Putty, в настройках программы указать настройки, которыми будет сконфигурирован программой ваш контроллер (либо указать значения, которыми сбрасываются регистры, если программа ничего не настраивает) и COM-порт, через который компьютер будет общаться с контроллером. Определить нужный COM-порт на операционной системе Windows можно через "Диспетчер устройств", который можно открыть через меню пуск.
В данном окне необходимо найти вкладку "Порты (COM и LPT)", раскрыть ее, а затем подключить отладочный стенд через USB-порт (если тот еще не был подключен). В списке появится новое устройство, а в скобках будет указан нужный COM-порт.
2. Не смотря на то, что описанный контроллер клавиатуры позволяет управлять клавиатурой с интерфейсом PS/2, некоторые платы (например Nexys A7) позволяют подключать вместо них клавиатуры с USB-интерфейсом. Дело в том, что PS/2 уже давно устарел и найти клавиатуры с таким интерфейсом — задача непростая. Однако протокол передачи по этому интерфейсу очень удобен для образовательны целей, поэтому некоторые производители просто ставят на платы переходник с USB на PS/2, позволяя объединить простоту разработки с удобством использования.
---

View File

@@ -0,0 +1,103 @@
/* -----------------------------------------------------------------------------
* Project Name : Architectures of Processor Systems (APS) lab work
* Organization : National Research University of Electronic Technology (MIET)
* Department : Institute of Microdevices and Control Systems
* Author(s) : Andrei Solodovnikov
* Email(s) : hepoh@org.miet.ru
See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
module lab_13_tb_system();
import peripheral_pkg::*;
logic clk_i;
logic resetn;
logic [15:0] sw_i;
logic [15:0] led_o;
logic ps2_clk;
logic ps2_dat;
logic [ 6:0] hex_led_o;
logic [ 7:0] hex_sel_o;
logic rx_i;
logic tx_o;
initial begin clk_i = 0; end
always #5ns clk_i = ~clk_i;
initial #4ms $finish();
initial begin
resetn = 1;
repeat(20)@(posedge clk_i);
resetn = 0;
repeat(20) @(posedge clk_i);
resetn = 1;
end
riscv_unit dut(
.clk_i (clk_i ),
.resetn_i (resetn ),
.sw_i (sw_i ),
.led_o (led_o ),
.kclk_i (ps2_clk ),
.kdata_i (ps2_dat ),
.hex_led_o(hex_led_o),
.hex_sel_o(hex_sel_o),
.rx_i (rx_i ),
.tx_o (tx_o )
);
initial begin: sw_block
sw_i = 16'd0;
repeat(1000) @(posedge clk_i);
sw_i = 16'hdead;
repeat(1000) @(posedge clk_i);
sw_i = 16'h5555;
repeat(1000) @(posedge clk_i);
sw_i = 16'hbeef;
repeat(1000) @(posedge clk_i);
sw_i = 16'haaaa;
end
initial begin: ps2_initial_block
ps2_clk = 1'b1;
ps2_dat = 1'b1;
repeat(1000) @(posedge clk_i);
ps2_send_scan_code(8'h1C, ps2_clk, ps2_dat);
repeat(1000) @(posedge clk_i);
ps2_send_scan_code(8'hf0, ps2_clk, ps2_dat);
repeat(1000) @(posedge clk_i);
ps2_send_scan_code(8'h1C, ps2_clk, ps2_dat);
repeat(1000) @(posedge clk_i);
ps2_send_scan_code(8'h32, ps2_clk, ps2_dat);
repeat(1000) @(posedge clk_i);
ps2_send_scan_code(8'hf0, ps2_clk, ps2_dat);
repeat(1000) @(posedge clk_i);
ps2_send_scan_code(8'h32, ps2_clk, ps2_dat);
repeat(1000) @(posedge clk_i);
ps2_send_scan_code(8'h21, ps2_clk, ps2_dat);
repeat(1000) @(posedge clk_i);
ps2_send_scan_code(8'hf0, ps2_clk, ps2_dat);
repeat(1000) @(posedge clk_i);
ps2_send_scan_code(8'h21, ps2_clk, ps2_dat);
end
initial begin: uart_rx_initial_block
rx_i = 1'b1;
repeat(1000) @(posedge clk_i);
uart_rx_send_char(8'h1c, 115200, rx_i);
repeat(1000) @(posedge clk_i);
uart_rx_send_char(8'h0D, 115200, rx_i);
repeat(1000) @(posedge clk_i);
uart_rx_send_char(8'h0D, 115200, rx_i);
repeat(1000) @(posedge clk_i);
uart_rx_send_char(8'h7F, 115200, rx_i);
repeat(1000) @(posedge clk_i);
uart_rx_send_char(8'h7F, 115200, rx_i);
end
endmodule

View File

@@ -0,0 +1,42 @@
/* -----------------------------------------------------------------------------
* Project Name : Architectures of Processor Systems (APS) lab work
* Organization : National Research University of Electronic Technology (MIET)
* Department : Institute of Microdevices and Control Systems
* Author(s) : Andrei Solodovnikov
* Email(s) : hepoh@org.miet.ru
See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
package peripheral_pkg;
localparam DMEM_ADDR_HIGH = 8'h00;
localparam SW_ADDR_HIGH = 8'h01;
localparam LED_ADDR_HIGH = 8'h02;
localparam PS2_ADDR_HIGH = 8'h03;
localparam HEX_ADDR_HIGH = 8'h04;
localparam RX_ADDR_HIGH = 8'h05;
localparam TX_ADDR_HIGH = 8'h06;
localparam VGA_ADDR_HIGH = 8'h07;
localparam TIMER_ADDR_HIGH = 8'h08;
task automatic ps2_send_scan_code(input logic [7:0] code, ref logic ps2_clk, ref logic ps2_dat);
logic [11:0] data = {2'b11, !(^code), code, 1'b0};
for(int i = 0; i < 11; i++) begin
ps2_dat = data[i];
#15us;
ps2_clk = 1'b0;
#15us;
ps2_clk = 1'b1;
end
endtask
task automatic uart_rx_send_char(input logic [7:0] char, input logic [31:0] baudrate, ref logic tx);
logic [11:0] data = {2'b11, (^char), char, 1'b0};
for(int i = 0; i < 12; i++) begin
tx = data[i];
#(1s/baudrate);
end
endtask
endpackage

View File

@@ -1,124 +0,0 @@
/* -----------------------------------------------------------------------------
* Project Name : Architectures of Processor Systems (APS) lab work
* Organization : National Research University of Electronic Technology (MIET)
* Department : Institute of Microdevices and Control Systems
* Author(s) : Andrei Solodovnikov
* Email(s) : hepoh@org.miet.ru
See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
* ------------------------------------------------------------------------------
*/
module tb_riscv_unit();
logic clk;
logic ps2_clk;
logic ps2_dat;
logic resetn;
logic [15:0] sw_i;
logic [15:0] led_o;
logic parity;
logic starter;
logic [ 6:0] hex_led_o;
logic [ 7:0] hex_sel_o;
logic rx_i;
logic tx_o;
logic [3:0] cntr;
initial begin clk = 0; ps2_clk = 0; end
always #5ns clk = ~clk;
always #50000 if(starter || (cntr > 0)) ps2_clk = ~ps2_clk; else ps2_clk = 1;
logic [11:0] data, uart_data;
initial #6ms $finish();
initial begin
resetn = 1;
repeat(20)@(posedge clk);
resetn = 0;
repeat(20) @(posedge clk);
resetn = 1;
end
riscv_unit dut(
.clk_i (clk ),
.resetn_i (resetn ),
.sw_i (sw_i ),
.led_o (led_o ),
.kclk_i (ps2_clk ),
.kdata_i (ps2_dat ),
.hex_led_o(hex_led_o),
.hex_sel_o(hex_sel_o),
.rx_i (rx_i ),
.tx_o (tx_o )
);
initial begin: sw_block
sw_i = 16'd0;
repeat(1000) @(posedge clk);
sw_i = 16'hdead;
repeat(1000) @(posedge clk);
sw_i = 16'h5555;
repeat(1000) @(posedge clk);
sw_i = 16'hbeef;
repeat(1000) @(posedge clk);
sw_i = 16'haaaa;
end
always @(negedge ps2_clk) begin: ps2_always_block
if(starter || (cntr > 0))
if(cntr == 10)
cntr <= 0;
else
cntr <= cntr + 1;
end
assign ps2_dat = cntr>0? data[cntr-1] : 1;
initial begin: ps2_initial_block
cntr = 0;
starter = 0;
data = 0;
repeat(10000) @(posedge clk);
ps2_send_scan_code(8'h1c);
ps2_send_scan_code(8'he0);
ps2_send_scan_code(8'hf0);
ps2_send_scan_code(8'h1c);
ps2_send_scan_code(8'h5c);
end
task ps2_send_scan_code(input logic [7:0] code);
data = {2'b11, !(^code), code, 1'b0};
starter = 1;
@(posedge ps2_clk);
starter = 0;
repeat(10) @(posedge ps2_clk);
endtask
initial begin: uart_rx_initial_block
uart_data = '1;
repeat(1000) @(posedge clk);
uart_rx_send_char(8'h1c, 115200);
uart_rx_send_char(8'h0D, 115200);
uart_rx_send_char(8'h0D, 115200);
uart_rx_send_char(8'h7F, 115200);
uart_rx_send_char(8'h7F, 115200);
end
assign rx_i = uart_data[0];
int uart_cntr;
task uart_rx_send_char(input logic [7:0] char, input logic [31:0] baudrate);
uart_data = {2'b11, (^char), char, 1'b0};
uart_cntr = 0;
while(uart_cntr <= 15) begin
#(1s/baudrate);
uart_data = {1'b1, uart_data[11:1]};
uart_cntr++;
end
endtask
endmodule