diff --git a/README.md b/README.md index 6b6ce44..3778bd1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Простой бенчмарк HDL симуляторов (преранняя версия) -Для оценки скорости запускается симуляция софт-процессора -[PicoRV32](https://github.com/YosysHQ/picorv32) с программой вычисления первых 200 -знаков числа Пи. +Для оценки скорости запускается симуляция 1024 софт-процессоров +[PicoRV32](https://github.com/YosysHQ/picorv32) с программой вычисления хэш-суммы MD5 +от блока 64кБ. Данные в каждом блоке инициализируются разными значениями. В папке `source` находятся исходники RTL и программы. Верхний модуль - `testbench` с единственным входным сигналом `clock`. Генерация клока во внешнем модуле сделана для @@ -12,51 +12,24 @@ симуляторе. Скрипты называются `__build.sh` (для сборки проекта) и `__run.sh` (для запуска симуляции). -Скрипт `run.sh` запускает бенчмарк на всех симуляторах и сохраняет время исполнения в -файл `results.txt`. Можно запустить бунчмарк на одном симуляторе, для чего в -параметрах скрипта `run.sh` нужно указать папку с бенчмарком. +Скрипт `run.sh` запускает бенчмарк из выбранной папки или все тесты, если параметром +указать `all`. Результаты бенчмарка записываются в файл `results.txt`. -## Результаты для 50 знаков Пи +## Результаты для 1024 процессоров - Xeon E5-2630v3 @ 2.40GHz - Verilator 5.011 devel rev v5.010-98-g15f8ebc56 - Icarus Verilog 13.0 (devel) (s20221226-127-gdeeac2edf) - ModelSim SE-64 2020.4 (Revision: 2020.10) +- QuestaSim 64 2021.1 (Revision: 2021.1) +- Vivado 2021.1 -Время в миллисекундах: +Время выполнения бенчмарка: ``` - test-iverilog: 210540 - test-modelsim: 25555 - test-verilator: 1289 + Icarus Verilog: TBD + ModelSim: TBD + QuestaSim: TBD + Verilator: TBD + XSIM: TBD + Xcelium: TBD ``` - -## Результаты для 200 знаков Пи - -Вычисление 200 знаков на Icarus Verilog занимает непозволительно много времени, по -этому перед запуском всех бенчмарков рекомендую переименовать папку `test-iverilog` в -`notest-iverilog`. - -Результаты для 200 знаков на том же процессоре: -``` - test-iverilog: 3257116 - test-xsim: 938296 - test-modelsim: 359562 - test-verilator: 20816 -``` - -## Предварительные результаты по симуляторам "Big 3" - -Коллеги прогнали бенчмарк на Xcelium, VCS и Modelsim. Примерные оценки показали -следующие результаты (приведено к скорости Xcelium): - -``` - test-verilator: 0.35 - test-xcelium: 1 - test-vcs: 1.37 - test-modelsim: 5.95 - test-xsim: 15.5 - test-iverilog: 58 -``` - -Конечно, нужно учитывать то, что Verilator - это cycle-accurate симулятор, и что он -не поддерживает состояния X и Z. diff --git a/run.sh b/run.sh index 1ad225c..bb18006 100755 --- a/run.sh +++ b/run.sh @@ -1,26 +1,31 @@ #!/usr/bin/env bash -set -e BUILD=__build.sh RUN=__run.sh -if [ -n "$1" ] +if [ "$1" == "all" ] +then + tests=$(ls -1d test-*) +elif [ -n "$1" ] then tests=$1 else - tests=$(ls -1d test-*) + echo "Usage: $0 " + exit -1 fi +## Log header echo >> results.txt echo "---------- Simulator's benchmark -----------" >> results.txt echo $(date) >> results.txt echo >> results.txt +## Run tests for test_dir in $tests do if [ ! -d "$test_dir" ] then - echo "Directory $test_dit is not exists. Break" + echo "Directory $test_dir is not exists" exit -1 fi @@ -29,15 +34,30 @@ do echo "#### Run benchmark in $test_dir" cd $test_dir + ./$BUILD - start_ms=$(date +%s%N | cut -b1-13) - ./$RUN - stop_ms=$(date +%s%N | cut -b1-13) + if [ $? -eq 0 ] + then + start_ms=$(date +%s%N | cut -b1-13) + + ./$RUN + if [ $? -eq 0 ] + then + stop_ms=$(date +%s%N | cut -b1-13) + ms=$(expr $stop_ms - $start_ms) + echo "#### $test_dir: $ms milliseconds" + else + ms="RUN FAIL" + echo "#### $test_dir: run fail" + fi + else + ms="BUILD FAIL" + echo "#### $test_dir: build fail" + fi + + echo "" cd .. - ms=$(expr $stop_ms - $start_ms) - echo "#### $test_dir: $ms milliseconds" - echo echo "$test_dir: $ms" >> results.txt else echo "Skip $test_dir directory" diff --git a/source/bus_mux.v b/source/bus_mux.v index fccef29..a94dc6e 100644 --- a/source/bus_mux.v +++ b/source/bus_mux.v @@ -2,11 +2,13 @@ // Slaves address ranges: // 0 - 0x00000000-0x0000ffff -// 1 - 0x01000000-0x01000fff +// 1 - 0x00010000-0x0001ffff +// 2 - 0x01000000-0x01000fff // i_slave_rdata bits: // 0: i_slave_rdata[31:0] // 1: i_slave_rdata[63:32] +// 2: i_slave_rdata[95:64] module bus_mux (input wire clock, @@ -23,32 +25,38 @@ module bus_mux output wire o_ready, // Slaves interface - input wire [63:0] i_slave_rdata, - output wire [1:0] o_slave_valid, - input wire [1:0] i_slave_ready); + input wire [95:0] i_slave_rdata, + output wire [2:0] o_slave_valid, + input wire [2:0] i_slave_ready); - wire [1:0] selector; - reg [1:0] selector_reg; + wire [2:0] selector; + reg [2:0] selector_reg; always @(posedge clock) if (reset) - selector_reg <= 2'd0; + selector_reg <= 3'd0; else if (!i_valid) selector_reg <= selector; assign selector[0] = + i_la_addr[16] == 1'b0 && i_la_addr[24] == 1'b0; assign selector[1] = + i_la_addr[16] == 1'b1 && + i_la_addr[24] == 1'b0; + + assign selector[2] = i_la_addr[24] == 1'b1; - assign o_slave_valid = selector_reg & {2{i_valid}}; + assign o_slave_valid = selector_reg & {3{i_valid}}; assign o_ready = |(i_slave_ready & selector_reg); assign o_rdata = (i_slave_rdata[31:0] & {32{selector_reg[0]}}) | - (i_slave_rdata[63:32] & {32{selector_reg[1]}}); + (i_slave_rdata[63:32] & {32{selector_reg[1]}}) | + (i_slave_rdata[95:64] & {32{selector_reg[2]}}); `ifdef FORMAL @@ -57,7 +65,7 @@ module bus_mux ones = 0; // Check for selector is zero or one-hot value - for (n = 0; n < 2; n = n + 1) + for (n = 0; n < 3; n = n + 1) if (selector[n] == 1'b1) ones = ones + 1; @@ -66,27 +74,34 @@ module bus_mux // Check for correct address ranges decode if (i_la_addr >= 32'h0 && i_la_addr <= 32'hffff) assert(selector[0] == 1'b1); - if (i_la_addr >= 32'h1000000 && i_la_addr <= 32'h1000fff) + if (i_la_addr >= 32'h10000 && i_la_addr <= 32'h1ffff) assert(selector[1] == 1'b1); + if (i_la_addr >= 32'h1000000 && i_la_addr <= 32'h1000fff) + assert(selector[2] == 1'b1); end // Check multiplexer always @(*) begin : formal_mux case (selector_reg) - 2'b01: begin + 3'b001: begin assert(o_rdata == i_slave_rdata[31:0]); assert(o_ready == i_slave_ready[0]); assert(o_slave_valid[0] == i_valid); end - 2'b10: begin + 3'b010: begin assert(o_rdata == i_slave_rdata[63:32]); assert(o_ready == i_slave_ready[1]); assert(o_slave_valid[1] == i_valid); end - 2'b00: begin + 3'b100: begin + assert(o_rdata == i_slave_rdata[95:64]); + assert(o_ready == i_slave_ready[2]); + assert(o_slave_valid[2] == i_valid); + end + 3'b000: begin assert(o_rdata == 32'd0); assert(o_ready == 1'b0); - assert(o_slave_valid == 2'd0); + assert(o_slave_valid == 3'd0); end endcase end diff --git a/source/firmware/.gitignore b/source/firmware/.gitignore index 2e4deda..1667bea 100644 --- a/source/firmware/.gitignore +++ b/source/firmware/.gitignore @@ -2,3 +2,4 @@ *.bin *.map *.asm +compile_flags.txt diff --git a/source/firmware/Makefile b/source/firmware/Makefile index 67cf6d1..ecdfe13 100644 --- a/source/firmware/Makefile +++ b/source/firmware/Makefile @@ -1,21 +1,12 @@ PROJECT := fw -SOURCES := crt0.s main.c uprintf.c +SOURCES := crt0.s main.c uprintf.c md5.c CPU_RAM_REG := ram_reg ARCH := riscv32-none-elf CFLAGS := -O2 -Wall -march=rv32i -mabi=ilp32 -mstrict-align \ - -nostartfiles \ - -ffunction-sections -lgcc \ + -nostartfiles -ffunction-sections -lgcc \ -Wl,-Tpicorv32-minimal.ld,-static,-Map,$(PROJECT).map -# CFLAGS := -O3 -Wall -march=rv32i -mabi=ilp32 -mstrict-align \ -# -nostartfiles \ -# -ffunction-sections \ -# -ffreestanding -lgcc \ -# -Wl,-T,picorv32-minimal.ld,-static,-Map,$(PROJECT).map - -# -nostdlib - ELF = $(PROJECT).elf BIN = $(PROJECT).bin ASM = $(PROJECT).asm diff --git a/source/firmware/fw.mem b/source/firmware/fw.mem index dcab966..d31d8df 100644 --- a/source/firmware/fw.mem +++ b/source/firmware/fw.mem @@ -1,188 +1,29 @@ 00010117 ffc10113 00010433 -0780006f +0140006f 10056513 010007b7 -00a7a223 +00a7aa23 00008067 -00050593 -00001537 -ff010113 -c0850513 -00812423 -00112623 -00001437 -151000ef -75042783 -00400713 -00178793 -74f42823 -00e78a63 -00c12083 -00812403 -01010113 -00008067 -00001537 -c0c50513 -121000ef -00c12083 -74042823 -00812403 -01010113 -00008067 -00001537 -fb010113 -0c800593 -c1050513 -03812423 -04112623 -04812423 -04912223 -05212023 -03312e23 -03412c23 -03512a23 -03612823 -03712623 -03912223 -03a12023 -01b12e23 -0c5000ef -000017b7 -00001737 -ce478c13 -a6c70713 -ce478793 -00ec0733 -00200693 -00d7a023 -00478793 -fee79ce3 -00001bb7 -0c800a13 -00012623 -00000993 -00001ab7 -00001937 -74cb8b93 -00900c93 -00400b13 -000b8d13 -53500493 -29b00413 -00000d93 -000d2683 -000d8593 -00040513 -00269793 -00d787b3 -00179d93 -165000ef -00ad8db3 -00048593 -000d8513 -1fd000ef -00050693 -00048593 -000d8513 -00dd2023 -165000ef -fff40413 -00050d93 -ffcd0d13 -ffe48493 -fa0418e3 -00a00593 -1cd000ef -00050713 -00a00593 -000d8513 -00ec2023 -135000ef -00050413 -0b950263 -00a00793 -0af50e63 -00c12583 -c08a8513 -7dc000ef -75092783 -00178793 -74f92823 -05678063 -05304863 -00812623 -00000993 -fffa0a13 -f40a12e3 -00c12583 -c08a8513 -7ac000ef -00001537 -c3850513 -7a0000ef +fe010113 +00010613 +01000593 +00010537 +00112e23 +40d000ef +00012703 010007b7 +00e7a223 +00412703 +00e7a423 +00812703 +00e7a623 +00c12703 +00e7a823 00100713 00e7a023 0000006f -000017b7 -c0c78513 -784000ef -74092823 -fb305ce3 -00000493 -00900593 -c08a8513 -76c000ef -75092783 -00148493 -00178793 -74f92823 -01678a63 -ff3490e3 -f8dff06f -00198993 -f8dff06f -000017b7 -c0c78513 -73c000ef -74092823 -fd3490e3 -f6dff06f -00c12783 -c08a8513 -00178593 -720000ef -75092783 -00178793 -74f92823 -05678a63 -03305663 -00000413 -00000593 -c08a8513 -6fc000ef -75092783 -00140413 -00178793 -74f92823 -01678a63 -ff3410e3 -00012623 -00000993 -f1dff06f -000017b7 -c0c78513 -6cc000ef -74092823 -fd3410e3 -fe1ff06f -000017b7 -c0c78513 -6b4000ef -74092823 -fa1ff06f fe010113 00912a23 01212823 @@ -225,7 +66,7 @@ ff244ae3 00158513 40c00433 02048c63 -7f0000ef +615000ef 00150b13 f88b58e3 fff40413 @@ -401,7 +242,7 @@ ff877713 06d76e63 00001737 00269693 -c4070713 +fb070713 00e68733 00072703 00070067 @@ -447,7 +288,7 @@ f49ff06f 0a088463 fcd51ae3 00001b37 -cc4b0793 +034b0793 00471713 16084a63 01c10693 @@ -458,11 +299,11 @@ cc4b0793 00f12623 00098593 00040513 -3e8000ef +069000ef 00a12423 00098593 00040513 -390000ef +011000ef 00c12783 00812703 000b0593 @@ -488,7 +329,7 @@ ce0402e3 dadff06f 0ad51463 00001b37 -cc4b0793 +034b0793 00471713 01c10693 00e787b3 @@ -498,11 +339,11 @@ cc4b0793 00f12623 00098593 00040513 -348000ef +7c8000ef 00a12423 00098593 00040513 -2f0000ef +770000ef 00c12783 00812703 000b0593 @@ -551,11 +392,11 @@ e49ff06f 00f12623 00098593 00040513 -274000ef +6f4000ef 00a12423 00098593 00040513 -21c000ef +69c000ef 00c12783 00812703 000b0893 @@ -633,7 +474,7 @@ ffffffb7 00001e37 00001637 ffffcf13 -3cc00313 +15000313 01010e93 81060613 800e0e13 @@ -679,14 +520,302 @@ ffffcf13 01812503 06010113 00008067 -00050613 -00000513 -0015f693 -00068463 -00c50533 -0015d593 -00161613 -fe0596e3 +40b007b3 +00b515b3 +00f55533 +00b56533 +00008067 +00000793 +00f52023 +674527b7 +30178793 +00f52423 +efcdb7b7 +b8978793 +00f52623 +98bae7b7 +cfe78793 +00f52823 +103257b7 +00000813 +47678793 +01052223 +00f52a23 +00008067 +fe010113 +00c52383 +00812e23 +00912c23 +00852403 +00452483 +01212a23 +00052903 +000018b7 +05488893 +01312823 +01412623 +01512423 +01612223 +01712023 +10088313 +00038613 +00040813 +00048713 +00090a13 +00000f13 +00500e93 +00100e13 +00000693 +00100993 +00200293 +04000f93 +0700006f +0a0a8263 +0107c7b3 +00ff7a93 +002a9a93 +0008ab83 +01558ab3 +000aab03 +00032a83 +017787b3 +016787b3 +014787b3 +41500a33 +01579ab3 +0147d7b3 +00faeab3 +00168693 +00ea8ab3 +00060a13 +00488893 +00430313 +005e0e13 +003e8e93 +007f0f13 +05f68e63 +00080613 +00070813 +000a8713 +0046da93 +033a8063 +fff64793 +00e7e7b3 +f85a92e3 +010747b3 +00c7c7b3 +00fefa93 +f81ff06f +010747b3 +00c7f7b3 +0107c7b3 +00fe7a93 +f6dff06f +00c847b3 +00e7f7b3 +00c7c7b3 +00068a93 +f59ff06f +00e40433 +00852423 +01c12403 +015484b3 +00c90933 +010383b3 +01252023 +00952223 +00752623 +01812483 +01412903 +01012983 +00c12a03 +00812a83 +00412b03 +00012b83 +02010113 +00008067 +fa010113 +04912a23 +00052483 +00452683 +04112e23 +00960733 +00c737b3 +04812c23 +05212823 +05312623 +05412423 +05512223 +00d787b3 +00e52023 +00f52223 +08060c63 +00050a13 +03f4f493 +00058913 +00c58ab3 +04010993 +00850413 +0100006f +00190913 +00078493 +072a8863 +00094683 +009a0733 +00148793 +00d70c23 +03f7f493 +fe0490e3 +018a0713 +00010693 +00374783 +00274803 +00074883 +00174603 +01879793 +01081813 +0107e7b3 +0117e7b3 +00861613 +00c7e7b3 +00f6a023 +00468693 +00470713 +fcd996e3 +00010593 +00040513 +00190913 +dc5ff0ef +f92a9ce3 +05c12083 +05812403 +05412483 +05012903 +04c12983 +04812a03 +04412a83 +06010113 +00008067 +00052603 +fb010113 +04812423 +04112623 +04912223 +05212023 +03700793 +03f67613 +00050413 +12c7e463 +03800793 +40c78933 +000015b7 +00090613 +25458593 +00040513 +ec9ff0ef +00042703 +00442783 +01840493 +41270633 +00c73733 +40e78333 +00c42023 +00642223 +00048713 +00010693 +03810893 +00374783 +00274803 +00074503 +00174583 +01879793 +01081813 +0107e7b3 +00a7e7b3 +00859593 +00b7e7b3 +00f6a023 +00468693 +00470713 +fd1696e3 +01d65713 +00331793 +00840413 +00361613 +00f767b3 +00010593 +00040513 +02c12c23 +02f12e23 +ccdff0ef +ffff0837 +ff0105b7 +01000637 +00040513 +0ff80813 +fff58593 +fff60613 +00052703 +00450513 +00875693 +0ff77793 +0ff6f693 +00869693 +0107f7b3 +00d7e7b3 +00ff06b7 +00d776b3 +00b7f7b3 +00d7e7b3 +01875713 +01871713 +00c7f7b3 +00e7e7b3 +04f52623 +faa49ee3 +04c12083 +04812403 +04412483 +04012903 +05010113 +00008067 +07800793 +40c78933 +eddff06f +f8010113 +00058793 +06812c23 +00060413 +00078613 +00000793 +00f12423 +674527b7 +30178793 +00f12823 +efcdb7b7 +b8978793 +00f12a23 +98bae7b7 +cfe78793 +00f12c23 +103257b7 +00050593 +00000813 +47678793 +00810513 +06112e23 +01012623 +00f12e23 +d51ff0ef +00810513 +e41ff0ef +06010593 +00040513 +01000613 +0c8000ef +07c12083 +07812403 +08010113 00008067 06054063 0605c663 @@ -733,6 +862,111 @@ fe0558e3 f61ff0ef 40b00533 00028067 +00b547b3 +0037f793 +00c508b3 +06079463 +00300793 +06c7f063 +00357793 +00050713 +06079a63 +ffc8f613 +40e606b3 +02000793 +08d7ce63 +00058693 +00070793 +02c77863 +0006a803 +00478793 +00468693 +ff07ae23 +fec7e8e3 +fff60793 +40e787b3 +ffc7f793 +00478793 +00f70733 +00f585b3 +01176863 +00008067 +00050713 +05157863 +0005c783 +00170713 +00158593 +fef70fa3 +fee898e3 +00008067 +0005c683 +00170713 +00377793 +fed70fa3 +00158593 +f6078ee3 +0005c683 +00170713 +00377793 +fed70fa3 +00158593 +fc079ae3 +f61ff06f +00008067 +ff010113 +00812623 +02000413 +0005a383 +0045a283 +0085af83 +00c5af03 +0105ae83 +0145ae03 +0185a303 +01c5a803 +0205a683 +02470713 +40e607b3 +fc772e23 +fe572023 +fff72223 +ffe72423 +ffd72623 +ffc72823 +fe672a23 +ff072c23 +fed72e23 +02458593 +faf446e3 +00058693 +00070793 +02c77863 +0006a803 +00478793 +00468693 +ff07ae23 +fec7e8e3 +fff60793 +40e787b3 +ffc7f793 +00478793 +00f70733 +00f585b3 +01176863 +00c12403 +01010113 +00008067 +0005c783 +00170713 +00158593 +fef70fa3 +fee882e3 +0005c783 +00170713 +00158593 +fef70fa3 +fce89ee3 +fcdff06f 00357793 00050713 04079c63 @@ -768,53 +1002,39 @@ ffd78513 00008067 ffc78513 00008067 -00006425 -0000000a -6d6f430a -61747570 -6e6f6974 -20666f20 -66206425 -74737269 -67696420 -20737469 -5020666f -00000a49 -4e4f440a -00000a45 -00000874 -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -0000085c -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -00000850 -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -000006bc -00000868 +000005f8 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +000005e0 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +000005d4 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +00000440 +000005ec 33323130 37363534 42413938 @@ -823,355 +1043,135 @@ ffc78513 37363534 62613938 66656463 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 -00000000 +d76aa478 +e8c7b756 +242070db +c1bdceee +f57c0faf +4787c62a +a8304613 +fd469501 +698098d8 +8b44f7af +ffff5bb1 +895cd7be +6b901122 +fd987193 +a679438e +49b40821 +f61e2562 +c040b340 +265e5a51 +e9b6c7aa +d62f105d +02441453 +d8a1e681 +e7d3fbc8 +21e1cde6 +c33707d6 +f4d50d87 +455a14ed +a9e3e905 +fcefa3f8 +676f02d9 +8d2a4c8a +fffa3942 +8771f681 +6d9d6122 +fde5380c +a4beea44 +4bdecfa9 +f6bb4b60 +bebfbc70 +289b7ec6 +eaa127fa +d4ef3085 +04881d05 +d9d4d039 +e6db99e5 +1fa27cf8 +c4ac5665 +f4292244 +432aff97 +ab9423a7 +fc93a039 +655b59c3 +8f0ccc92 +ffeff47d +85845dd1 +6fa87e4f +fe2ce6e0 +a3014314 +4e0811a1 +f7537e82 +bd3af235 +2ad7d2bb +eb86d391 +00000007 +0000000c +00000011 +00000016 +00000007 +0000000c +00000011 +00000016 +00000007 +0000000c +00000011 +00000016 +00000007 +0000000c +00000011 +00000016 +00000005 +00000009 +0000000e +00000014 +00000005 +00000009 +0000000e +00000014 +00000005 +00000009 +0000000e +00000014 +00000005 +00000009 +0000000e +00000014 +00000004 +0000000b +00000010 +00000017 +00000004 +0000000b +00000010 +00000017 +00000004 +0000000b +00000010 +00000017 +00000004 +0000000b +00000010 +00000017 +00000006 +0000000a +0000000f +00000015 +00000006 +0000000a +0000000f +00000015 +00000006 +0000000a +0000000f +00000015 +00000006 +0000000a +0000000f +00000015 +00000080 00000000 00000000 00000000 diff --git a/source/firmware/main.c b/source/firmware/main.c index c22ace5..2b4f57b 100644 --- a/source/firmware/main.c +++ b/source/firmware/main.c @@ -1,82 +1,27 @@ #include "../io_reg.h" +#include "md5.h" #include "uprintf.h" #include +#define DATA_ADDR 0x10000 +#define DATA_LEN 0x10000 + void put_char(char c) { IO_REG_CONSOLE = c | IO_REG_CONSOLE_SEND; } -#define N 200 -#define CHUNK 4 -#define ARR_LEN (10 * N / 3 + 1) - -static int arr[ARR_LEN]; - -void print_digit(int d) +int main(void) { - static int cnt = 0; + uint8_t result[16]; - p("%d", d); - cnt++; + md5Buf((uint8_t *)DATA_ADDR, DATA_LEN, result); - if (cnt == CHUNK) { - p("\n"); - cnt = 0; - } -} - -/* See: https://en.wikipedia.org/wiki/Spigot_algorithm */ - -int main() -{ - p("\nComputation of %d first digits of PI\n", N); - - for (int i = 0; i < ARR_LEN; i++) - arr[i] = 2; - - int nines = 0; - int predigit = 0; - - for (int j = 1; j < N + 1; j++) { - int q = 0; - - for (int i = ARR_LEN; i > 0; i--) { - int x = 10 * arr[i - 1] + q * i; - arr[i - 1] = x % (2 * i - 1); - q = x / (2 * i - 1); - } - - arr[0] = q % 10; - q = q / 10; - - if (9 == q) - nines++; - else if (10 == q) { - print_digit(predigit + 1); - - for (int k = 0; k < nines; k++) - print_digit(0); - - predigit = 0; - nines = 0; - } - else { - print_digit(predigit); - predigit = q; - - if (0 != nines) { - for (int k = 0; k < nines; k++) - print_digit(9); - - nines = 0; - } - } - } - p("%d", predigit); - - p("\nDONE\n"); + IO_REG_MD5_OUT0 = *(uint32_t *)(result + 0); + IO_REG_MD5_OUT1 = *(uint32_t *)(result + 4); + IO_REG_MD5_OUT2 = *(uint32_t *)(result + 8); + IO_REG_MD5_OUT3 = *(uint32_t *)(result + 12); /* Stop simulation */ IO_REG_CTRL = IO_REG_CTRL_STOP; diff --git a/source/firmware/md5.c b/source/firmware/md5.c new file mode 100644 index 0000000..9d79bd1 --- /dev/null +++ b/source/firmware/md5.c @@ -0,0 +1,210 @@ +/* + * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm + * and modified slightly to be functionally identical but condensed into control + * structures. + */ + +#include "md5.h" + +#include + +/* + * Constants defined by the MD5 algorithm + */ +#define A 0x67452301 +#define B 0xefcdab89 +#define C 0x98badcfe +#define D 0x10325476 + +static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, + 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, + 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, + 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; + +static uint32_t K[] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, + 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, + 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, + 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, + 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, + 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; + +/* + * Padding used to make the size (in bits) of the input congruent to 448 mod 512 + */ +static uint8_t PADDING[] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* + * Bit-manipulation functions defined by the MD5 algorithm + */ +#define F(X, Y, Z) ((X & Y) | (~X & Z)) +#define G(X, Y, Z) ((X & Z) | (Y & ~Z)) +#define H(X, Y, Z) (X ^ Y ^ Z) +#define I(X, Y, Z) (Y ^ (X | ~Z)) + +/* + * Rotates a 32-bit word left by n bits + */ +uint32_t rotateLeft(uint32_t x, uint32_t n) +{ + return (x << n) | (x >> (32 - n)); +} + +/* + * Initialize a context + */ +void md5Init(MD5Context *ctx) +{ + ctx->size = (uint64_t)0; + + ctx->buffer[0] = (uint32_t)A; + ctx->buffer[1] = (uint32_t)B; + ctx->buffer[2] = (uint32_t)C; + ctx->buffer[3] = (uint32_t)D; +} + +/* + * Add some amount of input to the context + * + * If the input fills out a block of 512 bits, apply the algorithm (md5Step) + * and save the result in the buffer. Also updates the overall size. + */ +void md5Update(MD5Context *ctx, uint8_t *input_buffer, size_t input_len) +{ + uint32_t input[16]; + unsigned int offset = ctx->size % 64; + ctx->size += (uint64_t)input_len; + + // Copy each byte in input_buffer into the next space in our context input + for (unsigned int i = 0; i < input_len; ++i) { + ctx->input[offset++] = (uint8_t) * (input_buffer + i); + + // If we've filled our context input, copy it into our local array input + // then reset the offset to 0 and fill in a new buffer. + // Every time we fill out a chunk, we run it through the algorithm + // to enable some back and forth between cpu and i/o + if (offset % 64 == 0) { + for (unsigned int j = 0; j < 16; ++j) { + // Convert to little-endian + // The local variable `input` our 512-bit chunk separated into + // 32-bit words we can use in calculations + input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 | + (uint32_t)(ctx->input[(j * 4) + 2]) << 16 | + (uint32_t)(ctx->input[(j * 4) + 1]) << 8 | + (uint32_t)(ctx->input[(j * 4)]); + } + md5Step(ctx->buffer, input); + offset = 0; + } + } +} + +/* + * Pad the current input to get to 448 bytes, append the size in bits to the + * very end, and save the result of the final iteration into digest. + */ +void md5Finalize(MD5Context *ctx) +{ + uint32_t input[16]; + unsigned int offset = ctx->size % 64; + unsigned int padding_length = + offset < 56 ? 56 - offset : (56 + 64) - offset; + + // Fill in the padding and undo the changes to size that resulted from the + // update + md5Update(ctx, PADDING, padding_length); + ctx->size -= (uint64_t)padding_length; + + // Do a final update (internal to this function) + // Last two 32-bit words are the two halves of the size (converted from + // bytes to bits) + for (unsigned int j = 0; j < 14; ++j) { + input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 | + (uint32_t)(ctx->input[(j * 4) + 2]) << 16 | + (uint32_t)(ctx->input[(j * 4) + 1]) << 8 | + (uint32_t)(ctx->input[(j * 4)]); + } + input[14] = (uint32_t)(ctx->size * 8); + input[15] = (uint32_t)((ctx->size * 8) >> 32); + + md5Step(ctx->buffer, input); + + // Move the result into digest (convert from little-endian) + for (unsigned int i = 0; i < 4; ++i) { + ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF)); + ctx->digest[(i * 4) + 1] = + (uint8_t)((ctx->buffer[i] & 0x0000FF00) >> 8); + ctx->digest[(i * 4) + 2] = + (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16); + ctx->digest[(i * 4) + 3] = + (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24); + } +} + +/* + * Step on 512 bits of input with the main MD5 algorithm. + */ +void md5Step(uint32_t *buffer, uint32_t *input) +{ + uint32_t AA = buffer[0]; + uint32_t BB = buffer[1]; + uint32_t CC = buffer[2]; + uint32_t DD = buffer[3]; + + uint32_t E; + + unsigned int j; + + for (unsigned int i = 0; i < 64; ++i) { + switch (i / 16) { + case 0: + E = F(BB, CC, DD); + j = i; + break; + case 1: + E = G(BB, CC, DD); + j = ((i * 5) + 1) % 16; + break; + case 2: + E = H(BB, CC, DD); + j = ((i * 3) + 5) % 16; + break; + default: + E = I(BB, CC, DD); + j = (i * 7) % 16; + break; + } + + uint32_t temp = DD; + DD = CC; + CC = BB; + BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]); + AA = temp; + } + + buffer[0] += AA; + buffer[1] += BB; + buffer[2] += CC; + buffer[3] += DD; +} + +void md5Buf(uint8_t *input, int len, uint8_t *result) +{ + MD5Context ctx; + md5Init(&ctx); + md5Update(&ctx, input, len); + md5Finalize(&ctx); + memcpy(result, ctx.digest, 16); +} diff --git a/source/firmware/md5.h b/source/firmware/md5.h new file mode 100644 index 0000000..8d3c741 --- /dev/null +++ b/source/firmware/md5.h @@ -0,0 +1,24 @@ +#ifndef MD5_H +#define MD5_H + +#include +#include +#include +#include + +typedef struct +{ + uint64_t size; // Size of input in bytes + uint32_t buffer[4]; // Current accumulation of hash + uint8_t input[64]; // Input to be used in the next step + uint8_t digest[16]; // Result of algorithm +} MD5Context; + +void md5Init(MD5Context *ctx); +void md5Update(MD5Context *ctx, uint8_t *input, size_t input_len); +void md5Finalize(MD5Context *ctx); +void md5Step(uint32_t *buffer, uint32_t *input); + +void md5Buf(uint8_t *input, int len, uint8_t *result); + +#endif diff --git a/source/firmware/shell.nix b/source/firmware/shell.nix index e27f756..db41406 100644 --- a/source/firmware/shell.nix +++ b/source/firmware/shell.nix @@ -7,10 +7,12 @@ let cross-rv5 = import { libc = "newlib"; }; }; + flags-file = "compile_flags.txt"; in cross-rv5.mkShell { nativeBuildInputs = [ nixpkgs.gnumake nixpkgs.guile_3_0 ]; shellHook = '' export NIX_SHELL_NAME="riscv" + echo | riscv32-none-elf-gcc -E -Wp,-v - 2>&1 | grep "^ .*newlib" | sed 's/^ /-I/' > ${flags-file} ''; } diff --git a/source/generate.sh b/source/generate.sh index f20902b..6ed1df2 100755 --- a/source/generate.sh +++ b/source/generate.sh @@ -4,5 +4,5 @@ set -e ../scripts/register-gen.scm io.reg > io_reg.v ../scripts/register-gen.scm -c io.reg > io_reg.h ../scripts/register-gen.scm -t io.reg > io_reg.txt -../scripts/picorv32-bus-mux-gen.scm -s 0+0x10000 -s 0x01000000+0x1000 -m bus_mux > bus_mux.v -../scripts/picorv32-bus-mux-gen.scm -s 0+0x10000 -s 0x01000000+0x1000 -m bus_mux -f > bus_mux.sby +../scripts/picorv32-bus-mux-gen.scm -s 0+0x10000 -s 0x10000+0x10000 -s 0x01000000+0x1000 -m bus_mux > bus_mux.v +../scripts/picorv32-bus-mux-gen.scm -s 0+0x10000 -s 0x10000+0x10000 -s 0x01000000+0x1000 -m bus_mux -f > bus_mux.sby diff --git a/source/io.reg b/source/io.reg index 7ef937b..fbf8b22 100644 --- a/source/io.reg +++ b/source/io.reg @@ -9,6 +9,22 @@ (info "Control register") (bits 1 "stop" w (reset #b0))) + (reg "md5_out0" + (info "Bytes 0..3 of MD5 sum") + (bits 32 "data" w)) + + (reg "md5_out1" + (info "Bytes 4..7 of MD5 sum") + (bits 32 "data" w)) + + (reg "md5_out2" + (info "Bytes 8..11 of MD5 sum") + (bits 32 "data" w)) + + (reg "md5_out3" + (info "Bytes 12..15 of MD5 sum") + (bits 32 "data" w)) + (reg "console" read-notify (info "Virtual console port") (bits 8 "data" rw (info "Read/write char from/to console")) diff --git a/source/io_reg.h b/source/io_reg.h index df69c76..4a8c266 100644 --- a/source/io_reg.h +++ b/source/io_reg.h @@ -7,8 +7,28 @@ #define IO_REG_CTRL (*(volatile uint32_t*)(IO_REG_BASE + 0x00000000)) #define IO_REG_CTRL_STOP (1 << 0) +/* -- Register 'MD5_OUT0' -- */ +#define IO_REG_MD5_OUT0 (*(volatile uint32_t*)(IO_REG_BASE + 0x00000004)) +#define IO_REG_MD5_OUT0_DATA__MASK 0xffffffff +#define IO_REG_MD5_OUT0_DATA__SHIFT 0 + +/* -- Register 'MD5_OUT1' -- */ +#define IO_REG_MD5_OUT1 (*(volatile uint32_t*)(IO_REG_BASE + 0x00000008)) +#define IO_REG_MD5_OUT1_DATA__MASK 0xffffffff +#define IO_REG_MD5_OUT1_DATA__SHIFT 0 + +/* -- Register 'MD5_OUT2' -- */ +#define IO_REG_MD5_OUT2 (*(volatile uint32_t*)(IO_REG_BASE + 0x0000000c)) +#define IO_REG_MD5_OUT2_DATA__MASK 0xffffffff +#define IO_REG_MD5_OUT2_DATA__SHIFT 0 + +/* -- Register 'MD5_OUT3' -- */ +#define IO_REG_MD5_OUT3 (*(volatile uint32_t*)(IO_REG_BASE + 0x00000010)) +#define IO_REG_MD5_OUT3_DATA__MASK 0xffffffff +#define IO_REG_MD5_OUT3_DATA__SHIFT 0 + /* -- Register 'CONSOLE' -- */ -#define IO_REG_CONSOLE (*(volatile uint32_t*)(IO_REG_BASE + 0x00000004)) +#define IO_REG_CONSOLE (*(volatile uint32_t*)(IO_REG_BASE + 0x00000014)) #define IO_REG_CONSOLE_DATA__MASK 0x000000ff #define IO_REG_CONSOLE_DATA__SHIFT 0 #define IO_REG_CONSOLE_SEND (1 << 8) diff --git a/source/io_reg.txt b/source/io_reg.txt index 1cd6ee8..89137c0 100644 --- a/source/io_reg.txt +++ b/source/io_reg.txt @@ -1,10 +1,14 @@ Register map of IO_REG (base: 0x1000000) ======================================== - | Offset | Name | Description | - |------------+---------+----------------------| - | 0x00000000 | CTRL | Control register | - | 0x00000004 | CONSOLE | Virtual console port | + | Offset | Name | Description | + |------------+----------+-------------------------| + | 0x00000000 | CTRL | Control register | + | 0x00000004 | MD5_OUT0 | Bytes 0..3 of MD5 sum | + | 0x00000008 | MD5_OUT1 | Bytes 4..7 of MD5 sum | + | 0x0000000c | MD5_OUT2 | Bytes 8..11 of MD5 sum | + | 0x00000010 | MD5_OUT3 | Bytes 12..15 of MD5 sum | + | 0x00000014 | CONSOLE | Virtual console port | CTRL Register (0x00000000) @@ -17,7 +21,47 @@ CTRL Register (0x00000000) | 0 | STOP | WO | 0 | | -CONSOLE Register (0x00000004) +MD5_OUT0 Register (0x00000004) +------------------------------ + + Bytes 0..3 of MD5 sum + + | Bits | Name | Mode | Reset | Description | + |------+------+------+-------+-------------| + | 31:0 | DATA | WO | 0 | | + + +MD5_OUT1 Register (0x00000008) +------------------------------ + + Bytes 4..7 of MD5 sum + + | Bits | Name | Mode | Reset | Description | + |------+------+------+-------+-------------| + | 31:0 | DATA | WO | 0 | | + + +MD5_OUT2 Register (0x0000000c) +------------------------------ + + Bytes 8..11 of MD5 sum + + | Bits | Name | Mode | Reset | Description | + |------+------+------+-------+-------------| + | 31:0 | DATA | WO | 0 | | + + +MD5_OUT3 Register (0x00000010) +------------------------------ + + Bytes 12..15 of MD5 sum + + | Bits | Name | Mode | Reset | Description | + |------+------+------+-------+-------------| + | 31:0 | DATA | WO | 0 | | + + +CONSOLE Register (0x00000014) ----------------------------- Virtual console port diff --git a/source/io_reg.v b/source/io_reg.v index 13829c1..25e0cf8 100644 --- a/source/io_reg.v +++ b/source/io_reg.v @@ -17,6 +17,18 @@ module io_reg /* ---- 'ctrl' ---- */ output wire o_ctrl_stop, + /* ---- 'md5_out0' ---- */ + output wire [31:0] o_md5_out0_data, + + /* ---- 'md5_out1' ---- */ + output wire [31:0] o_md5_out1_data, + + /* ---- 'md5_out2' ---- */ + output wire [31:0] o_md5_out2_data, + + /* ---- 'md5_out3' ---- */ + output wire [31:0] o_md5_out3_data, + /* ---- 'console' ---- */ output wire o_console__rnotify, input wire [7:0] i_console_data, @@ -28,13 +40,39 @@ module io_reg /* ---- Address decoder ---- */ wire ctrl_select; + wire md5_out0_select; + wire md5_out1_select; + wire md5_out2_select; + wire md5_out3_select; wire console_select; assign ctrl_select = - i_addr[2] == 1'b0; + i_addr[2] == 1'b0 && + i_addr[3] == 1'b0 && + i_addr[4] == 1'b0; + + assign md5_out0_select = + i_addr[2] == 1'b1 && + i_addr[3] == 1'b0 && + i_addr[4] == 1'b0; + + assign md5_out1_select = + i_addr[2] == 1'b0 && + i_addr[3] == 1'b1 && + i_addr[4] == 1'b0; + + assign md5_out2_select = + i_addr[2] == 1'b1 && + i_addr[3] == 1'b1 && + i_addr[4] == 1'b0; + + assign md5_out3_select = + i_addr[2] == 1'b0 && + i_addr[4] == 1'b1; assign console_select = - i_addr[2] == 1'b1; + i_addr[2] == 1'b1 && + i_addr[4] == 1'b1; /* ---- 'ctrl' ---- */ @@ -50,6 +88,70 @@ module io_reg end + /* ---- 'md5_out0' ---- */ + reg [31:0] md5_out0_data; + assign o_md5_out0_data = md5_out0_data; + + always @(posedge clock) + if (reset) + md5_out0_data <= 32'b0; + else + if (md5_out0_select && i_write) begin + if (i_ben[0]) md5_out0_data[7:0] <= i_data[7:0]; + if (i_ben[1]) md5_out0_data[15:8] <= i_data[15:8]; + if (i_ben[2]) md5_out0_data[23:16] <= i_data[23:16]; + if (i_ben[3]) md5_out0_data[31:24] <= i_data[31:24]; + end + + + /* ---- 'md5_out1' ---- */ + reg [31:0] md5_out1_data; + assign o_md5_out1_data = md5_out1_data; + + always @(posedge clock) + if (reset) + md5_out1_data <= 32'b0; + else + if (md5_out1_select && i_write) begin + if (i_ben[0]) md5_out1_data[7:0] <= i_data[7:0]; + if (i_ben[1]) md5_out1_data[15:8] <= i_data[15:8]; + if (i_ben[2]) md5_out1_data[23:16] <= i_data[23:16]; + if (i_ben[3]) md5_out1_data[31:24] <= i_data[31:24]; + end + + + /* ---- 'md5_out2' ---- */ + reg [31:0] md5_out2_data; + assign o_md5_out2_data = md5_out2_data; + + always @(posedge clock) + if (reset) + md5_out2_data <= 32'b0; + else + if (md5_out2_select && i_write) begin + if (i_ben[0]) md5_out2_data[7:0] <= i_data[7:0]; + if (i_ben[1]) md5_out2_data[15:8] <= i_data[15:8]; + if (i_ben[2]) md5_out2_data[23:16] <= i_data[23:16]; + if (i_ben[3]) md5_out2_data[31:24] <= i_data[31:24]; + end + + + /* ---- 'md5_out3' ---- */ + reg [31:0] md5_out3_data; + assign o_md5_out3_data = md5_out3_data; + + always @(posedge clock) + if (reset) + md5_out3_data <= 32'b0; + else + if (md5_out3_select && i_write) begin + if (i_ben[0]) md5_out3_data[7:0] <= i_data[7:0]; + if (i_ben[1]) md5_out3_data[15:8] <= i_data[15:8]; + if (i_ben[2]) md5_out3_data[23:16] <= i_data[23:16]; + if (i_ben[3]) md5_out3_data[31:24] <= i_data[31:24]; + end + + /* ---- 'console' ---- */ reg [7:0] console_data; assign o_console_data = console_data; @@ -77,14 +179,26 @@ module io_reg /* ---- Read multiplexer ---- */ reg [31:0] data_ctrl; + reg [31:0] data_md5_out0; + reg [31:0] data_md5_out1; + reg [31:0] data_md5_out2; + reg [31:0] data_md5_out3; reg [31:0] data_console; assign o_data = data_ctrl | + data_md5_out0 | + data_md5_out1 | + data_md5_out2 | + data_md5_out3 | data_console; always @(*) begin data_ctrl = 32'd0; + data_md5_out0 = 32'd0; + data_md5_out1 = 32'd0; + data_md5_out2 = 32'd0; + data_md5_out3 = 32'd0; data_console = 32'd0; if (console_select) begin diff --git a/source/md5calculator.sv b/source/md5calculator.sv new file mode 100644 index 0000000..5b923cd --- /dev/null +++ b/source/md5calculator.sv @@ -0,0 +1,226 @@ +`timescale 1ps/1ps + +module md5calculator + (input clock, + input reset, + output done, + // input [31:0] data_in, + output [127:0] md5); + + parameter MEM_ADDR_WIDTH = 16; + parameter ROM_ADDR_WIDTH = 16; + + /* verilator lint_off UNUSED */ + logic cpu_mem_valid; + logic cpu_mem_instr; + logic cpu_mem_ready; + logic [31:0] cpu_mem_addr; + logic [31:0] cpu_mem_wdata; + logic [ 3:0] cpu_mem_wstrb; + logic [31:0] cpu_mem_rdata; + + // Look-Ahead Interface + logic cpu_mem_la_read; + logic cpu_mem_la_write; + logic [31:0] cpu_mem_la_addr; + logic [31:0] cpu_mem_la_wdata; + logic [ 3:0] cpu_mem_la_wstrb; + /* verilator lint_on UNUSED */ + + // PicoRV32 // Defaults + picorv32 #(.ENABLE_COUNTERS(0), // = 1, + .ENABLE_COUNTERS64(0), // = 1, + .ENABLE_REGS_16_31(1), // = 1, + .ENABLE_REGS_DUALPORT(1), // = 1, + .LATCHED_MEM_RDATA(0), // = 0, + .TWO_STAGE_SHIFT(1), // = 1, + .BARREL_SHIFTER(0), // = 0, + .TWO_CYCLE_COMPARE(0), // = 0, + .TWO_CYCLE_ALU(0), // = 0, + .COMPRESSED_ISA(0), // = 0, + .CATCH_MISALIGN(1), // = 1, + .CATCH_ILLINSN(1), // = 1, + .ENABLE_PCPI(0), // = 0, + .ENABLE_MUL(0), // = 0, + .ENABLE_FAST_MUL(0), // = 0, + .ENABLE_DIV(0), // = 0, + .ENABLE_IRQ(0), // = 0, + .ENABLE_IRQ_QREGS(0), // = 1, + .ENABLE_IRQ_TIMER(0), // = 1, + .ENABLE_TRACE(0), // = 0, + .REGS_INIT_ZERO(0), // = 0, + .MASKED_IRQ(32'h 0000_0000), // = 32'h 0000_0000, + .LATCHED_IRQ(32'h ffff_ffff), // = 32'h ffff_ffff, + .PROGADDR_RESET(32'h 0000_0000), // = 32'h 0000_0000, + .PROGADDR_IRQ(32'h 0000_0010), // = 32'h 0000_0010, + .STACKADDR(32'h ffff_ffff)) // = 32'h ffff_ffff + picorv32 + (.clk(clock), + .resetn(~reset), + + .mem_valid(cpu_mem_valid), // output reg + .mem_instr(cpu_mem_instr), // output reg + .mem_ready(cpu_mem_ready), // input + .mem_addr(cpu_mem_addr), // output reg [31:0] + .mem_wdata(cpu_mem_wdata), // output reg [31:0] + .mem_wstrb(cpu_mem_wstrb), // output reg [ 3:0] + .mem_rdata(cpu_mem_rdata), // input [31:0] + + // Look-Ahead Interface + .mem_la_read(cpu_mem_la_read), // output + .mem_la_write(cpu_mem_la_write), // output + .mem_la_addr(cpu_mem_la_addr), // output [31:0] + .mem_la_wdata(cpu_mem_la_wdata), // output reg [31:0] + .mem_la_wstrb(cpu_mem_la_wstrb), // output reg [ 3:0] + + // Unused + /* verilator lint_off PINCONNECTEMPTY */ + .pcpi_valid(), // output reg + .pcpi_insn(), // output reg [31:0] + .pcpi_rs1(), // output [31:0] + .pcpi_rs2(), // output [31:0] + .pcpi_wr(1'b0), // input + .pcpi_rd(32'd0), // input [31:0] + .pcpi_wait(1'b0), // input + .pcpi_ready(1'b0), // input + .irq(32'd0), // input [31:0] + .eoi(), // output reg [31:0] + .trap(), // output reg + .trace_valid(), // output reg + .trace_data() // output reg [35:0] + /* verilator lint_on PINCONNECTEMPTY */ + ); + + // -- Bus multiplexer + // Slaves address ranges: + // 0 - 0x00000000-0x0000ffff + // 1 - 0x00010000-0x0001ffff + // 2 - 0x01000000-0x01000fff + + // i_slave_rdata bits: + // 0: i_slave_rdata[31:0] + // 1: i_slave_rdata[63:32] + // 2: i_slave_rdata[95:64] + + logic [31:0] rdata_ram; + logic [31:0] rdata_rom; + logic [31:0] rdata_reg; + logic valid_ram; + logic ready_ram; + logic valid_rom; + logic ready_rom; + logic valid_reg; + logic ready_reg; + + bus_mux bus_mux + (.clock, .reset, + // CPU + .i_la_addr(cpu_mem_la_addr), + .o_rdata(cpu_mem_rdata), + .i_valid(cpu_mem_valid), + .o_ready(cpu_mem_ready), + // Slaves + .i_slave_rdata({rdata_reg, rdata_rom, rdata_ram}), + .o_slave_valid({valid_reg, valid_rom, valid_ram}), + .i_slave_ready({ready_reg, ready_rom, ready_ram})); + + // -- CPU memory + picorv32_tcm #(.ADDR_WIDTH(MEM_ADDR_WIDTH), + .USE_LOOK_AHEAD(1), + .USE_ADDR_MUX(0), + .MEM_INIT_FILE("../source/firmware/fw.mem")) + main_tcm + (.clock, .reset, + + /* PicoRV32 bus interface */ + .mem_valid(valid_ram), + .mem_ready(ready_ram), + .mem_addr(cpu_mem_addr[MEM_ADDR_WIDTH-1:0]), + .mem_wdata(cpu_mem_wdata), + .mem_wstrb(cpu_mem_wstrb), + .mem_rdata(rdata_ram), + .mem_la_addr(cpu_mem_la_addr[MEM_ADDR_WIDTH-1:0])); + + // -- DATA memory + picorv32_tcm #(.ADDR_WIDTH(ROM_ADDR_WIDTH), + .USE_LOOK_AHEAD(1), + .USE_ADDR_MUX(0)) + rom + (.clock, .reset, + + /* PicoRV32 bus interface */ + .mem_valid(valid_rom), + .mem_ready(ready_rom), + .mem_addr(cpu_mem_addr[MEM_ADDR_WIDTH-1:0]), + .mem_wdata(cpu_mem_wdata), + .mem_wstrb(cpu_mem_wstrb), + .mem_rdata(rdata_rom), + .mem_la_addr(cpu_mem_la_addr[MEM_ADDR_WIDTH-1:0])); + + // -- Registers + logic ctrl_stop; + logic [31:0] md5_out0; + logic [31:0] md5_out1; + logic [31:0] md5_out2; + logic [31:0] md5_out3; + logic [7:0] i_console_data; + logic [7:0] o_console_data; + logic console_send; + + logic reg_write; + logic reg_read; + + assign ready_reg = 1'b1; + assign reg_write = valid_reg & |(cpu_mem_wdata); + assign reg_read = valid_reg & &(~cpu_mem_wdata); + assign i_console_data = 8'ha5; + + assign done = ctrl_stop; + assign md5 = {md5_out3, md5_out2, md5_out1, md5_out0}; + + io_reg io_reg + (.clock, .reset, + + // CPU + .i_addr({16'd0, cpu_mem_addr[15:0]}), + .i_data(cpu_mem_wdata), + .o_data(rdata_reg), + .i_ben(cpu_mem_wstrb), + .i_write(reg_write), + .i_read(reg_read), + + // Ctrl + .o_ctrl_stop(ctrl_stop), + + // MD5 + // .i_md5_data_data(data_in), + .o_md5_out0_data(md5_out0), + .o_md5_out1_data(md5_out1), + .o_md5_out2_data(md5_out2), + .o_md5_out3_data(md5_out3), + + // Console + .i_console_data(i_console_data), + .o_console_data(o_console_data), + .o_console_send_hsreq(console_send), + + // Unused + /* verilator lint_off PINCONNECTEMPTY */ + .o_console__rnotify(), + .i_console_send_hsack(1'b1), + .i_console_send(1'b0), + .i_console_valid(1'b1) + /* verilator lint_on PINCONNECTEMPTY */ + ); + + // Print console output + initial + forever begin + @(posedge clock); + if (!reset && console_send) begin + $write("%c", o_console_data); + $fflush; + end + end + +endmodule // testbench diff --git a/source/sources.f b/source/sources.f index 6881938..7144246 100644 --- a/source/sources.f +++ b/source/sources.f @@ -2,4 +2,5 @@ ../source/io_reg.v ../source/picorv32_tcm.sv ../source/picorv32.v +../source/md5calculator.sv ../source/testbench.sv diff --git a/source/testbench.sv b/source/testbench.sv index eff8ef8..a3884d9 100644 --- a/source/testbench.sv +++ b/source/testbench.sv @@ -1,204 +1,47 @@ `timescale 1ps/1ps + module testbench (input clock); - parameter MEM_ADDR_WIDTH = 16; + localparam CPU_COUNT = 1024; - logic reset = 1'b1; + logic [CPU_COUNT-1:0] done_all; - /* verilator lint_off UNUSED */ - logic cpu_mem_valid; - logic cpu_mem_instr; - logic cpu_mem_ready; - logic [31:0] cpu_mem_addr; - logic [31:0] cpu_mem_wdata; - logic [ 3:0] cpu_mem_wstrb; - logic [31:0] cpu_mem_rdata; + for (genvar ncpu = 0; ncpu < CPU_COUNT; ncpu = ncpu + 1) begin : cpus + localparam logic [31:0] MD5IN = ncpu; - // Look-Ahead Interface - logic cpu_mem_la_read; - logic cpu_mem_la_write; - logic [31:0] cpu_mem_la_addr; - logic [31:0] cpu_mem_la_wdata; - logic [ 3:0] cpu_mem_la_wstrb; - /* verilator lint_on UNUSED */ + logic done; + logic reset; + logic [127:0] md5; - // PicoRV32 // Defaults - picorv32 #(.ENABLE_COUNTERS(0), // = 1, - .ENABLE_COUNTERS64(0), // = 1, - .ENABLE_REGS_16_31(1), // = 1, - .ENABLE_REGS_DUALPORT(1), // = 1, - .LATCHED_MEM_RDATA(0), // = 0, - .TWO_STAGE_SHIFT(1), // = 1, - .BARREL_SHIFTER(0), // = 0, - .TWO_CYCLE_COMPARE(0), // = 0, - .TWO_CYCLE_ALU(0), // = 0, - .COMPRESSED_ISA(0), // = 0, - .CATCH_MISALIGN(1), // = 1, - .CATCH_ILLINSN(1), // = 1, - .ENABLE_PCPI(0), // = 0, - .ENABLE_MUL(0), // = 0, - .ENABLE_FAST_MUL(0), // = 0, - .ENABLE_DIV(0), // = 0, - .ENABLE_IRQ(0), // = 0, - .ENABLE_IRQ_QREGS(0), // = 1, - .ENABLE_IRQ_TIMER(0), // = 1, - .ENABLE_TRACE(0), // = 0, - .REGS_INIT_ZERO(0), // = 0, - .MASKED_IRQ(32'h 0000_0000), // = 32'h 0000_0000, - .LATCHED_IRQ(32'h ffff_ffff), // = 32'h ffff_ffff, - .PROGADDR_RESET(32'h 0000_0000), // = 32'h 0000_0000, - .PROGADDR_IRQ(32'h 0000_0010), // = 32'h 0000_0010, - .STACKADDR(32'h ffff_ffff)) // = 32'h ffff_ffff - picorv32 - (.clk(clock), - .resetn(~reset), + assign done_all[ncpu] = done; - .mem_valid(cpu_mem_valid), // output reg - .mem_instr(cpu_mem_instr), // output reg - .mem_ready(cpu_mem_ready), // input - .mem_addr(cpu_mem_addr), // output reg [31:0] - .mem_wdata(cpu_mem_wdata), // output reg [31:0] - .mem_wstrb(cpu_mem_wstrb), // output reg [ 3:0] - .mem_rdata(cpu_mem_rdata), // input [31:0] + md5calculator cpu(.clock, .reset, .done, .md5); - // Look-Ahead Interface - .mem_la_read(cpu_mem_la_read), // output - .mem_la_write(cpu_mem_la_write), // output - .mem_la_addr(cpu_mem_la_addr), // output [31:0] - .mem_la_wdata(cpu_mem_la_wdata), // output reg [31:0] - .mem_la_wstrb(cpu_mem_la_wstrb), // output reg [ 3:0] + initial + for (int n = 0; n < (2 ** (cpu.rom.ADDR_WIDTH-2)); n += 1) + cpu.rom.ram[n] = ncpu; - // Unused - /* verilator lint_off PINCONNECTEMPTY */ - .pcpi_valid(), // output reg - .pcpi_insn(), // output reg [31:0] - .pcpi_rs1(), // output [31:0] - .pcpi_rs2(), // output [31:0] - .pcpi_wr(1'b0), // input - .pcpi_rd(32'd0), // input [31:0] - .pcpi_wait(1'b0), // input - .pcpi_ready(1'b0), // input - .irq(32'd0), // input [31:0] - .eoi(), // output reg [31:0] - .trap(), // output reg - .trace_valid(), // output reg - .trace_data() // output reg [35:0] - /* verilator lint_on PINCONNECTEMPTY */ - ); + initial begin + reset = 1'b1; + repeat($urandom % 5 + 2) @(posedge clock); + reset = 1'b0; + @(posedge clock); - // -- Bus multiplexer - // Slaves address ranges: - // 0 - 0x00000000-0x0000ffff - // 1 - 0x01000000-0x01000fff - - // i_slave_rdata bits: - // 0: i_slave_rdata[31:0] - // 1: i_slave_rdata[63:32] - - logic [31:0] rdata_ram; - logic [31:0] rdata_reg; - logic valid_ram; - logic ready_ram; - logic valid_reg; - logic ready_reg; - - bus_mux bus_mux - (.clock, .reset, - // CPU - .i_la_addr(cpu_mem_la_addr), - .o_rdata(cpu_mem_rdata), - .i_valid(cpu_mem_valid), - .o_ready(cpu_mem_ready), - // Slaves - .i_slave_rdata({rdata_reg, rdata_ram}), - .o_slave_valid({valid_reg, valid_ram}), - .i_slave_ready({ready_reg, ready_ram})); - - // -- CPU memory - picorv32_tcm #(.ADDR_WIDTH(MEM_ADDR_WIDTH), - .USE_LOOK_AHEAD(1), - .USE_ADDR_MUX(0), - .MEM_INIT_FILE("../source/firmware/fw.mem")) - picorv32_tcm - (.clock, .reset, - - /* PicoRV32 bus interface */ - .mem_valid(valid_ram), - .mem_ready(ready_ram), - .mem_addr(cpu_mem_addr[MEM_ADDR_WIDTH-1:0]), - .mem_wdata(cpu_mem_wdata), - .mem_wstrb(cpu_mem_wstrb), - .mem_rdata(rdata_ram), - .mem_la_addr(cpu_mem_la_addr[MEM_ADDR_WIDTH-1:0])); - - // -- Registers - // Reg 'ctrl' - logic ctrl_stop; - - // Reg 'console' - logic [7:0] i_console_data; - logic [7:0] o_console_data; - logic console_send; - - logic reg_write; - logic reg_read; - - assign ready_reg = 1'b1; - assign reg_write = valid_reg & |(cpu_mem_wdata); - assign reg_read = valid_reg & &(~cpu_mem_wdata); - assign i_console_data = 8'ha5; - - io_reg io_reg - (.clock, .reset, - - // CPU - .i_addr({16'd0, cpu_mem_addr[15:0]}), - .i_data(cpu_mem_wdata), - .o_data(rdata_reg), - .i_ben(cpu_mem_wstrb), - .i_write(reg_write), - .i_read(reg_read), - - // Reg 'ctrl' - .o_ctrl_stop(ctrl_stop), - - // Reg 'console' - .i_console_data(i_console_data), - .o_console_data(o_console_data), - .o_console_send_hsreq(console_send), - - // Unused - /* verilator lint_off PINCONNECTEMPTY */ - .o_console__rnotify(), - .i_console_send_hsack(1'b1), - .i_console_send(1'b0), - .i_console_valid(1'b1) - /* verilator lint_on PINCONNECTEMPTY */ - ); - - // Reset - localparam RESET_DURATION = 5; - - initial begin - repeat(RESET_DURATION) @(posedge clock); - reset = 1'b0; + while(!done) @(posedge clock); + $display("MD5(0x%x) = %x", MD5IN, md5); + end end - // Print console output - initial - forever begin - @(posedge clock); - if (!reset && console_send) begin - $write("%c", o_console_data); - $fflush; - end - end - // Wait for complete initial begin - while (reset || ctrl_stop == 1'b0) @(posedge clock); + $display("--- BENCH BEGIN ---"); + + repeat(5) @(posedge clock); + while ((&done_all) == 1'b0) @(posedge clock); @(posedge clock); + + $display("--- BENCH DONE ---"); $finish; end diff --git a/test-modelsim/__run.sh b/test-modelsim/__run.sh index 411a72d..926662f 100755 --- a/test-modelsim/__run.sh +++ b/test-modelsim/__run.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -vsim -c -batch -voptargs=+acc=npr -do "run -all" -quiet -lib testbench top +vsim -batch -voptargs=+acc=npr -do "run -all" -quiet -lib testbench top diff --git a/test-verilator/Makefile b/test-verilator/Makefile index 55ec486..3ee336e 100644 --- a/test-verilator/Makefile +++ b/test-verilator/Makefile @@ -6,7 +6,7 @@ INCLUDES = FLAGS = -Wno-WIDTH -cc --top-module $(TOP_MODULE) +1800-2017ext+sv \ --timing --Mdir $(TOP_MODULE) -o $(TOP_MODULE) -f $(FLAGS_FILE) \ - --timescale "1ps/1ps" --threads 1 + --timescale "1ps/1ps" --threads 1 -j 0 # FLAGS += --trace diff --git a/test-verilator/__build.sh b/test-verilator/__build.sh index c166fb2..381aa2b 100755 --- a/test-verilator/__build.sh +++ b/test-verilator/__build.sh @@ -2,4 +2,4 @@ set -e make clean -make +make OPT_FAST="-Os -march=native" VM_PARALLEL_BUILDS=0