diff --git a/Labs/15. Coremark/README.md b/Labs/15. Coremark/README.md index 89d5f67..c858605 100644 --- a/Labs/15. Coremark/README.md +++ b/Labs/15. Coremark/README.md @@ -53,7 +53,7 @@ |0x00 | R | [0:2⁶⁴-1] | Значение системного счетчика, доступное только для чтения | |0x04 | RW | [0:2⁶⁴-1] | Указание задержки, спустя которую таймер будет генерировать прерывание | |0x08 | RW | [0:2] | Указание режима генерации прерываний (выключен, заданное число раз, бесконечно) | -|0x0c | RW | [0:2³²] | Указание количества повторений генерации прерываний | +|0x0c | RW | [0:2³²-1] | Указание количества повторений генерации прерываний | |0x24 | W | 1 | Программный сброс | Прототип модуля следующий: @@ -265,25 +265,26 @@ Correct operation validated. See README.md for run and reporting rules. ## Порядок выполнения задания 1. [Опишите](#таймер) таймер в виде модуля `timer_sb_ctrl`. -2. Подключите данный модуль к системной шине. Сигнал прерывания этого модуля подключать не нужно. +2. Проверьте описанный модуль с помощью модуля [tb_timer](tb_timer.sv). +3. Подключите `timer_sb_ctrl` к системной шине. Сигнал прерывания этого модуля подключать не нужно. 2.1 В случае, если до этого в ЛР12 вашим устройством вывода было не UART TX, вам необходимо подключить к системной шине и готовый модуль [uart_tx_sb_ctrl](../Made-up%20modules/lab_12.uart_tx_sb_ctrl.sv). -3. Получите исходники программы Coremark. Для этого можно либо склонировать репозиторий, либо скачать его в виде архива со страницы: [https://github.com/eembc/coremark](https://github.com/eembc/coremark). -4. Добавьте реализацию платформозависимых функций программы coremark. Для этого в папке `barebones` необходимо: +4. Получите исходники программы Coremark. Для этого можно либо склонировать репозиторий, либо скачать его в виде архива со страницы: [https://github.com/eembc/coremark](https://github.com/eembc/coremark). +5. Добавьте реализацию платформозависимых функций программы coremark. Для этого в папке `barebones` необходимо: 1. в файле `core_portme.c`: 1. [реализовать](#реализация-функции-измеряющей-время) функцию `barebones_clock`, возвращающую текущее значение системного счетчика; 2. объявить макрос `CLOCKS_PER_SEC`, характеризующий тактовую частоту процессора; 3. [реализовать](#реализация-функции-первичной-настройки) функцию `portable_init`, выполняющую первичную инициализацию периферийных устройств до начала теста; 2. в файле `ee_printf.c` [реализовать](#реализация-вывода-очередного-символа-сообщения) функцию `uart_send_char`, отвечающую за отправку очередного символа сообщения о результате. -5. Добавьте с заменой в корень программы файлы [Makefile](Makefile), [linker_script.ld](linker_script.ld) и [startup.S](../13.%20Programming/startup.S). -6. Скомпилируйте программу вызовом `make`. +6. Добавьте с заменой в корень программы файлы [Makefile](Makefile), [linker_script.ld](linker_script.ld) и [startup.S](../13.%20Programming/startup.S). +7. Скомпилируйте программу вызовом `make`. 1. Если кросскомпилятор расположен не в директории `C:/riscv_cc`, перед вызовом `make` вам необходимо соответствующим образом отредактировать первую строчку в `Makefile`. 2. В случае отсутствия на компьютере утилиты `make`, вы можете самостоятельно скомпилировать программу вызовом команд, представленных в разделе ["Компиляция"](#компиляция). -7. Временно измените размер памяти инструкций до 64KiB. +8. Временно измените размер памяти инструкций до 64KiB. 1. Для этого необходимо изменить размер памяти инструкций с 1024 слов до 16384 слов. 2. Кроме того, необходимо изменить используемые индексы адреса с `[11:2]` на `[15:2]`. -8. Проинициализируйте память инструкций и память данных файлами "coremark_instr.mem" и "coremark_data.mem", полученными в ходе компиляции программы. -9. Выполните моделирование системы с помощью модуля [tb_coremark](tb_coremark). - 1. Результаты теста будут выведены приблизительно на `335ms` времени моделирования. +9. Проинициализируйте память инструкций и память данных файлами "coremark_instr.mem" и "coremark_data.mem", полученными в ходе компиляции программы. +10. Выполните моделирование системы с помощью модуля [tb_coremark](tb_coremark). + 1. Результаты теста будут выведены приблизительно на `335ms` времени моделирования.
10. Прочти меня после успешного завершения моделирования @@ -318,7 +319,7 @@ Iterations/Sec : <скрыто то получения результатов Это и есть так называемый "кормарк" — метрика данной программы. Результат нашего процессора: 3.88 кормарка. -Обычно, для сравнения между собой нескольких реализаций микроархитектур, более достоверной считается величина "кормарк / МГц", т.е. значение кормарка поделеное на тактовую частоту процессора. Дело в том, что можно реализовать какую-нибудь очень сложную архитектуру, которая будет выдавать очень хороший кормарк, но при этом будет иметь очень низкую частоту. Более того, при сравнении с другими результатами, необходимо учитывать флаги оптимизации, которые использовались при компиляции программы, поскольку они также влияют на результат. +Обычно, для сравнения между собой нескольких реализаций микроархитектур, более достоверной считается величина "кормарк / МГц", т.е. значение кормарка, поделеное на тактовую частоту процессора. Дело в том, что можно реализовать какую-нибудь очень сложную архитектуру, которая будет выдавать очень хороший кормарк, но при этом будет иметь очень низкую частоту. Более того, при сравнении с другими результатами, необходимо учитывать флаги оптимизации, которые использовались при компиляции программы, поскольку они также влияют на результат. Мы не будем уходить в дебри темных паттернов маркетинга и вместо этого будет оценивать производительность в лоб: сколько кормарков в секунду смог прогнать наш проц в сравнении с представленными результатами других систем вне зависимости от их оптимизаций. diff --git a/Labs/15. Coremark/tb_timer.sv b/Labs/15. Coremark/tb_timer.sv new file mode 100644 index 0000000..aca8092 --- /dev/null +++ b/Labs/15. Coremark/tb_timer.sv @@ -0,0 +1,95 @@ +module tb_timer(); + + logic clk_i; + logic rst_i; + logic req_i; + logic write_enable_i; + logic [31:0] addr_i; + logic [31:0] write_data_i; + logic [31:0] read_data_o; + logic ready_o; + logic interrupt_request_o; + +localparam SYS_CNT_ADDR = 32'h0000_0000; +localparam DELAY_ADDR = 32'h0000_0004; +localparam MODE_ADDR = 32'h0000_0008; +localparam REP_CNT_ADDR = 32'h0000_000C; +localparam RST_ADDR = 32'h0000_0024; + +localparam OFF = 32'd0; +localparam NTIMES = 32'd1; +localparam FOREVER = 32'd2; + +always #50ns clk_i = !clk_i; + +timer_sb_ctrl DUT(.*); + +initial begin + clk_i = 0; + rst_i = 0; + req_i = 0; + write_enable_i = 0; + addr_i = 0; + write_data_i = 0; + @(posedge clk_i); + rst_i = 1; + repeat(5) @(posedge clk_i); + rst_i = 0; + + test_ntimes(0, 0); + test_ntimes(0, 1); + test_ntimes(1, 0); + test_ntimes(1, 1); + test_ntimes(10, 1); + test_ntimes(10, 10); + test_forever(10); + write_req(MODE_ADDR, OFF); + test_ntimes(10, 10); + test_forever(10); + test_ntimes(10, 10); + $finish(); +end + +one_cycle_irq: assert property ( + @(posedge clk_i) disable iff ( rst_i || (DUT.delay==32'd1)) + (interrupt_request_o |=> !interrupt_request_o) +); + +task test_ntimes(input logic [31:0] delay, ntimes); + write_req(DELAY_ADDR, delay); + write_req(REP_CNT_ADDR, ntimes); + write_req(MODE_ADDR, NTIMES); + repeat(ntimes) begin + repeat(delay)@(posedge clk_i); + if(!interrupt_request_o & delay) begin + $error("test_ntimes: delay = %d, ntimes = %d", delay, ntimes); + end + end +endtask + +task test_forever(input logic [31:0] delay); + write_req(DELAY_ADDR, delay); + write_req(MODE_ADDR, FOREVER); + repeat(1000) begin + repeat(delay) @(posedge clk_i); + if(!interrupt_request_o) begin + $error("test_forever"); + end + end +endtask + +task write_req(input [31:0] addr, data); + @(posedge clk_i); + addr_i <= addr; + write_data_i <= data; + write_enable_i <= 1'b1; + req_i <= 1'b1; + @(posedge clk_i); + while(!ready_o) begin + @(posedge clk_i); + end + req_i <= 1'b0; + write_enable_i <= 1'b0; +endtask + +endmodule \ No newline at end of file