Compare commits
10 Commits
a3815caa0a
...
9283c009b4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9283c009b4 | ||
|
|
d8b140e939 | ||
|
|
a68a7b4790 | ||
|
|
142fb46b2f | ||
|
|
0cb0d82998 | ||
|
|
7afbe06799 | ||
|
|
7e96777b89 | ||
|
|
923a08b9a8 | ||
|
|
047bd9c42b | ||
|
|
89c82cb611 |
85
README.md
85
README.md
@ -1,8 +1,10 @@
|
|||||||
# Простой бенчмарк HDL симуляторов (преранняя версия)
|
# Простой бенчмарк HDL симуляторов (версия альфа)
|
||||||
|
|
||||||
Для оценки скорости запускается симуляция софт-процессора
|
Для оценки скорости запускается симуляция 1024 софт-процессоров
|
||||||
[PicoRV32](https://github.com/YosysHQ/picorv32) с программой вычисления первых 200
|
[PicoRV32](https://github.com/YosysHQ/picorv32) с программой вычисления хэш-суммы MD5
|
||||||
знаков числа Пи.
|
от блока 1кБ. Данные в каждом блоке инициализируются разными значениями. Размер блока
|
||||||
|
по-усолчанию равен 1кБ, но с помощью параметра `+dlen=NNN` можно установить
|
||||||
|
произвольный размер.
|
||||||
|
|
||||||
В папке `source` находятся исходники RTL и программы. Верхний модуль - `testbench` с
|
В папке `source` находятся исходники RTL и программы. Верхний модуль - `testbench` с
|
||||||
единственным входным сигналом `clock`. Генерация клока во внешнем модуле сделана для
|
единственным входным сигналом `clock`. Генерация клока во внешнем модуле сделана для
|
||||||
@ -12,51 +14,48 @@
|
|||||||
симуляторе. Скрипты называются `__build.sh` (для сборки проекта) и `__run.sh` (для
|
симуляторе. Скрипты называются `__build.sh` (для сборки проекта) и `__run.sh` (для
|
||||||
запуска симуляции).
|
запуска симуляции).
|
||||||
|
|
||||||
Скрипт `run.sh` запускает бенчмарк на всех симуляторах и сохраняет время исполнения в
|
Скрипт `run.sh` запускает бенчмарк из выбранной папки или все тесты. В параметрах
|
||||||
файл `results.txt`. Можно запустить бунчмарк на одном симуляторе, для чего в
|
можно указать количество софт-ядер, размер блока, количество потоков симуляции (пока
|
||||||
параметрах скрипта `run.sh` нужно указать папку с бенчмарком.
|
только для верилятора) и список бенчмарков:
|
||||||
|
|
||||||
## Результаты для 50 знаков Пи
|
```
|
||||||
|
$ ./run.sh -h
|
||||||
|
Usage: ./run.sh [OPTION]... [SIM...]
|
||||||
|
Run simulator benchmark. Calculates MD5 hash from a block data
|
||||||
|
on an array of soft-cores PicoRV32.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-c [COUNT] Soft CPU count in simulation. Default: 1024
|
||||||
|
-s [SIZE] Data block size in bytes. Default: 1024 bytes
|
||||||
|
-t [COUNT] Simulation threads count. Default: 1
|
||||||
|
(so far only for Verilator)
|
||||||
|
-l List of available benchmarks
|
||||||
|
-h This help
|
||||||
|
|
||||||
|
The SIM parameter is the name of the simulator from the list of
|
||||||
|
option -l. If the parameter is not specified, benchmarks for all
|
||||||
|
simulators will be performed. Be careful, some simulators take
|
||||||
|
a very long time to benchmark.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Результаты для 1024 процессоров
|
||||||
|
|
||||||
- Xeon E5-2630v3 @ 2.40GHz
|
- Xeon E5-2630v3 @ 2.40GHz
|
||||||
- Verilator 5.011 devel rev v5.010-98-g15f8ebc56
|
- Verilator 5.011 devel rev v5.010-98-g15f8ebc56
|
||||||
- Icarus Verilog 13.0 (devel) (s20221226-127-gdeeac2edf)
|
- Icarus Verilog 13.0 (devel) (s20221226-127-gdeeac2edf)
|
||||||
- ModelSim SE-64 2020.4 (Revision: 2020.10)
|
- ModelSim SE-64 2020.4 (Revision: 2020.10)
|
||||||
|
- QuestaSim 64 2021.1 (Revision: 2021.1)
|
||||||
|
- Vivado 2021.1
|
||||||
|
|
||||||
Время в миллисекундах:
|
Время выполнения бенчмарка на блоке 1кБ (чч:мм:сс):
|
||||||
```
|
```
|
||||||
test-iverilog: 210540
|
| Симулятор | Build | Run |
|
||||||
test-modelsim: 25555
|
+-----------------------+----------+----------+
|
||||||
test-verilator: 1289
|
| Icarus Verilog | 00:00:27 | 19:04:37 |
|
||||||
|
| ModelSim | 00:00:00 | 01:33:14 |
|
||||||
|
| QuestaSim | 00:00:00 | 01:29:38 |
|
||||||
|
| Verilator (1 thread) | 00:12:03 | 00:02:57 |
|
||||||
|
| Verilator (8 threads) | 00:18:45 | 00:01:33 |
|
||||||
|
| XSIM | 00:00:29 | 02:08:54 |
|
||||||
|
| 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.
|
|
||||||
|
|||||||
206
run.sh
206
run.sh
@ -1,45 +1,181 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
|
||||||
|
|
||||||
BUILD=__build.sh
|
## Default valies
|
||||||
RUN=__run.sh
|
CPU_COUNT=1024
|
||||||
|
BLOCK_SIZE=1024
|
||||||
|
THREADS=1
|
||||||
|
|
||||||
if [ -n "$1" ]
|
BLD_SCRIPT="__build.sh"
|
||||||
|
RUN_SCRIPT="__run.sh"
|
||||||
|
TEST_DIR_PREFIX="test-"
|
||||||
|
LOG_PREFIX="####"
|
||||||
|
|
||||||
|
function sim_dir_valid()
|
||||||
|
{
|
||||||
|
if [ -e "$1/$BLD_SCRIPT" ] && [ -e "$1/$RUN_SCRIPT" ]
|
||||||
|
then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function sim_list()
|
||||||
|
{
|
||||||
|
for dir in "$TEST_DIR_PREFIX"*
|
||||||
|
do
|
||||||
|
if sim_dir_valid "$dir"
|
||||||
|
then
|
||||||
|
echo "${dir:5}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function print_help()
|
||||||
|
{
|
||||||
|
echo "Usage: $0 [OPTION]... [SIM...]"
|
||||||
|
echo "Run simulator benchmark. Calculates MD5 hash from a block data"
|
||||||
|
echo "on an array of soft-cores PicoRV32."
|
||||||
|
echo
|
||||||
|
echo "Options:"
|
||||||
|
echo " -c [COUNT] Soft CPU count in simulation. Default: 1024"
|
||||||
|
echo " -s [SIZE] Data block size in bytes. Default: 1024 bytes"
|
||||||
|
echo " -t [COUNT] Simulation threads count. Default: 1"
|
||||||
|
echo " (so far only for Verilator)"
|
||||||
|
echo " -l List of available benchmarks"
|
||||||
|
echo " -h This help"
|
||||||
|
echo
|
||||||
|
echo "The SIM parameter is the name of the simulator from the list of"
|
||||||
|
echo "option -l. If the parameter is not specified, benchmarks for all"
|
||||||
|
echo "simulators will be performed. Be careful, some simulators take "
|
||||||
|
echo "a very long time to benchmark."
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_arg(){
|
||||||
|
if [[ $2 == -* ]]
|
||||||
|
then
|
||||||
|
echo "Option $1 requires an argument" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_param()
|
||||||
|
{
|
||||||
|
while getopts ":c:s:t:lh" opt
|
||||||
|
do
|
||||||
|
case $opt in
|
||||||
|
c)
|
||||||
|
check_arg "-c" "$OPTARG"
|
||||||
|
CPU_COUNT=$OPTARG
|
||||||
|
;;
|
||||||
|
s)
|
||||||
|
check_arg "-s" "$OPTARG"
|
||||||
|
BLOCK_SIZE=$OPTARG
|
||||||
|
;;
|
||||||
|
t)
|
||||||
|
check_arg "-t" "$OPTARG"
|
||||||
|
THREADS=$OPTARG
|
||||||
|
;;
|
||||||
|
l)
|
||||||
|
sim_list
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
h)
|
||||||
|
print_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "Invalid option: -$OPTARG" >&2
|
||||||
|
print_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
:)
|
||||||
|
echo "Option -$OPTARG requires an argument" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function log()
|
||||||
|
{
|
||||||
|
echo -n "$LOG_PREFIX "
|
||||||
|
echo "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_benchmark()
|
||||||
|
{
|
||||||
|
benchmark=$1
|
||||||
|
dir=$TEST_DIR_PREFIX$benchmark
|
||||||
|
|
||||||
|
if sim_dir_valid "$dir"
|
||||||
|
then
|
||||||
|
local t0 t1 ms
|
||||||
|
|
||||||
|
if cd "$dir"
|
||||||
|
then
|
||||||
|
# Build
|
||||||
|
log "Build $benchmark"
|
||||||
|
t0=$(date +%s%N | cut -b1-13)
|
||||||
|
|
||||||
|
if ! ./$BLD_SCRIPT "$CPU_COUNT" "$BLOCK_SIZE" "$THREADS"
|
||||||
|
then
|
||||||
|
cd ..
|
||||||
|
log "Build $benchmark FAILED"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
t1=$(date +%s%N | cut -b1-13)
|
||||||
|
ms=$((t1 - t0))
|
||||||
|
log "Build $benchmark time (ms): $ms"
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Run
|
||||||
|
log "Run $benchmark"
|
||||||
|
t0=$(date +%s%N | cut -b1-13)
|
||||||
|
|
||||||
|
if ! ./$RUN_SCRIPT "$CPU_COUNT" "$BLOCK_SIZE" "$THREADS"
|
||||||
|
then
|
||||||
|
cd ..
|
||||||
|
log "RUN $benchmark FAILED"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
t1=$(date +%s%N | cut -b1-13)
|
||||||
|
ms=$((t1 - t0))
|
||||||
|
log "Run $benchmark time (ms): $ms"
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
log "Can't change dir to $dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "No run scripts found in $dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_param "$@"
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
if [ $# -gt 0 ]
|
||||||
then
|
then
|
||||||
tests=$1
|
benches="$*"
|
||||||
else
|
else
|
||||||
tests=$(ls -1d test-*)
|
for b in $(sim_list); do benches="$benches$b "; done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo >> results.txt
|
log "Soft-cores count: $CPU_COUNT"
|
||||||
echo "---------- Simulator's benchmark -----------" >> results.txt
|
log "Block size: $BLOCK_SIZE"
|
||||||
echo $(date) >> results.txt
|
log "Threads count: $THREADS"
|
||||||
echo >> results.txt
|
log "Benchmarks: $benches"
|
||||||
|
|
||||||
for test_dir in $tests
|
for bench in $benches
|
||||||
do
|
do
|
||||||
if [ ! -d "$test_dir" ]
|
echo
|
||||||
then
|
run_benchmark "$bench"
|
||||||
echo "Directory $test_dit is not exists. Break"
|
|
||||||
exit -1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -e $test_dir/$BUILD -a -e $test_dir/$RUN ]
|
|
||||||
then
|
|
||||||
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)
|
|
||||||
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"
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|||||||
11
scripts/sim_vars.sh
Normal file
11
scripts/sim_vars.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
if [ $# -lt 3 ]
|
||||||
|
then
|
||||||
|
echo "Usage: $0 <CPU_COUNT> <BLOCK_SIZE> <THREADS_COUNT"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CPU_COUNT=$1
|
||||||
|
BLOCK_SIZE=$2
|
||||||
|
THREADS=$3
|
||||||
|
|
||||||
|
FFILE=../source/sources.f
|
||||||
@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
// Slaves address ranges:
|
// Slaves address ranges:
|
||||||
// 0 - 0x00000000-0x0000ffff
|
// 0 - 0x00000000-0x0000ffff
|
||||||
// 1 - 0x01000000-0x01000fff
|
// 1 - 0x00010000-0x0001ffff
|
||||||
|
// 2 - 0x01000000-0x01000fff
|
||||||
|
|
||||||
// i_slave_rdata bits:
|
// i_slave_rdata bits:
|
||||||
// 0: i_slave_rdata[31:0]
|
// 0: i_slave_rdata[31:0]
|
||||||
// 1: i_slave_rdata[63:32]
|
// 1: i_slave_rdata[63:32]
|
||||||
|
// 2: i_slave_rdata[95:64]
|
||||||
|
|
||||||
module bus_mux
|
module bus_mux
|
||||||
(input wire clock,
|
(input wire clock,
|
||||||
@ -23,32 +25,38 @@ module bus_mux
|
|||||||
output wire o_ready,
|
output wire o_ready,
|
||||||
|
|
||||||
// Slaves interface
|
// Slaves interface
|
||||||
input wire [63:0] i_slave_rdata,
|
input wire [95:0] i_slave_rdata,
|
||||||
output wire [1:0] o_slave_valid,
|
output wire [2:0] o_slave_valid,
|
||||||
input wire [1:0] i_slave_ready);
|
input wire [2:0] i_slave_ready);
|
||||||
|
|
||||||
wire [1:0] selector;
|
wire [2:0] selector;
|
||||||
reg [1:0] selector_reg;
|
reg [2:0] selector_reg;
|
||||||
|
|
||||||
always @(posedge clock)
|
always @(posedge clock)
|
||||||
if (reset)
|
if (reset)
|
||||||
selector_reg <= 2'd0;
|
selector_reg <= 3'd0;
|
||||||
else
|
else
|
||||||
if (!i_valid)
|
if (!i_valid)
|
||||||
selector_reg <= selector;
|
selector_reg <= selector;
|
||||||
|
|
||||||
assign selector[0] =
|
assign selector[0] =
|
||||||
|
i_la_addr[16] == 1'b0 &&
|
||||||
i_la_addr[24] == 1'b0;
|
i_la_addr[24] == 1'b0;
|
||||||
|
|
||||||
assign selector[1] =
|
assign selector[1] =
|
||||||
|
i_la_addr[16] == 1'b1 &&
|
||||||
|
i_la_addr[24] == 1'b0;
|
||||||
|
|
||||||
|
assign selector[2] =
|
||||||
i_la_addr[24] == 1'b1;
|
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_ready = |(i_slave_ready & selector_reg);
|
||||||
|
|
||||||
assign o_rdata =
|
assign o_rdata =
|
||||||
(i_slave_rdata[31:0] & {32{selector_reg[0]}}) |
|
(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
|
`ifdef FORMAL
|
||||||
|
|
||||||
@ -57,7 +65,7 @@ module bus_mux
|
|||||||
ones = 0;
|
ones = 0;
|
||||||
|
|
||||||
// Check for selector is zero or one-hot value
|
// 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)
|
if (selector[n] == 1'b1)
|
||||||
ones = ones + 1;
|
ones = ones + 1;
|
||||||
|
|
||||||
@ -66,27 +74,34 @@ module bus_mux
|
|||||||
// Check for correct address ranges decode
|
// Check for correct address ranges decode
|
||||||
if (i_la_addr >= 32'h0 && i_la_addr <= 32'hffff)
|
if (i_la_addr >= 32'h0 && i_la_addr <= 32'hffff)
|
||||||
assert(selector[0] == 1'b1);
|
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);
|
assert(selector[1] == 1'b1);
|
||||||
|
if (i_la_addr >= 32'h1000000 && i_la_addr <= 32'h1000fff)
|
||||||
|
assert(selector[2] == 1'b1);
|
||||||
end
|
end
|
||||||
|
|
||||||
// Check multiplexer
|
// Check multiplexer
|
||||||
always @(*) begin : formal_mux
|
always @(*) begin : formal_mux
|
||||||
case (selector_reg)
|
case (selector_reg)
|
||||||
2'b01: begin
|
3'b001: begin
|
||||||
assert(o_rdata == i_slave_rdata[31:0]);
|
assert(o_rdata == i_slave_rdata[31:0]);
|
||||||
assert(o_ready == i_slave_ready[0]);
|
assert(o_ready == i_slave_ready[0]);
|
||||||
assert(o_slave_valid[0] == i_valid);
|
assert(o_slave_valid[0] == i_valid);
|
||||||
end
|
end
|
||||||
2'b10: begin
|
3'b010: begin
|
||||||
assert(o_rdata == i_slave_rdata[63:32]);
|
assert(o_rdata == i_slave_rdata[63:32]);
|
||||||
assert(o_ready == i_slave_ready[1]);
|
assert(o_ready == i_slave_ready[1]);
|
||||||
assert(o_slave_valid[1] == i_valid);
|
assert(o_slave_valid[1] == i_valid);
|
||||||
end
|
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_rdata == 32'd0);
|
||||||
assert(o_ready == 1'b0);
|
assert(o_ready == 1'b0);
|
||||||
assert(o_slave_valid == 2'd0);
|
assert(o_slave_valid == 3'd0);
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|||||||
1
source/firmware/.gitignore
vendored
1
source/firmware/.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
*.bin
|
*.bin
|
||||||
*.map
|
*.map
|
||||||
*.asm
|
*.asm
|
||||||
|
compile_flags.txt
|
||||||
|
|||||||
@ -1,21 +1,12 @@
|
|||||||
PROJECT := fw
|
PROJECT := fw
|
||||||
SOURCES := crt0.s main.c uprintf.c
|
SOURCES := crt0.s main.c uprintf.c md5.c
|
||||||
CPU_RAM_REG := ram_reg
|
CPU_RAM_REG := ram_reg
|
||||||
|
|
||||||
ARCH := riscv32-none-elf
|
ARCH := riscv32-none-elf
|
||||||
CFLAGS := -O2 -Wall -march=rv32i -mabi=ilp32 -mstrict-align \
|
CFLAGS := -O2 -Wall -march=rv32i -mabi=ilp32 -mstrict-align \
|
||||||
-nostartfiles \
|
-nostartfiles -ffunction-sections -lgcc \
|
||||||
-ffunction-sections -lgcc \
|
|
||||||
-Wl,-Tpicorv32-minimal.ld,-static,-Map,$(PROJECT).map
|
-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
|
ELF = $(PROJECT).elf
|
||||||
BIN = $(PROJECT).bin
|
BIN = $(PROJECT).bin
|
||||||
ASM = $(PROJECT).asm
|
ASM = $(PROJECT).asm
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
|||||||
#include "../io_reg.h"
|
#include "../io_reg.h"
|
||||||
|
#include "md5.h"
|
||||||
#include "uprintf.h"
|
#include "uprintf.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -8,75 +9,21 @@ void put_char(char c)
|
|||||||
IO_REG_CONSOLE = c | IO_REG_CONSOLE_SEND;
|
IO_REG_CONSOLE = c | IO_REG_CONSOLE_SEND;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define N 200
|
int main(void)
|
||||||
#define CHUNK 4
|
|
||||||
#define ARR_LEN (10 * N / 3 + 1)
|
|
||||||
|
|
||||||
static int arr[ARR_LEN];
|
|
||||||
|
|
||||||
void print_digit(int d)
|
|
||||||
{
|
{
|
||||||
static int cnt = 0;
|
uint8_t result[16];
|
||||||
|
uint8_t *daddr;
|
||||||
|
uint32_t dlen;
|
||||||
|
|
||||||
p("%d", d);
|
daddr = (uint8_t *)IO_REG_DATA_ADDR;
|
||||||
cnt++;
|
dlen = IO_REG_DATA_LEN;
|
||||||
|
|
||||||
if (cnt == CHUNK) {
|
md5Buf(daddr, dlen, result);
|
||||||
p("\n");
|
|
||||||
cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See: https://en.wikipedia.org/wiki/Spigot_algorithm */
|
IO_REG_MD5_OUT0 = *(uint32_t *)(result + 0);
|
||||||
|
IO_REG_MD5_OUT1 = *(uint32_t *)(result + 4);
|
||||||
int main()
|
IO_REG_MD5_OUT2 = *(uint32_t *)(result + 8);
|
||||||
{
|
IO_REG_MD5_OUT3 = *(uint32_t *)(result + 12);
|
||||||
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");
|
|
||||||
|
|
||||||
/* Stop simulation */
|
/* Stop simulation */
|
||||||
IO_REG_CTRL = IO_REG_CTRL_STOP;
|
IO_REG_CTRL = IO_REG_CTRL_STOP;
|
||||||
|
|||||||
210
source/firmware/md5.c
Normal file
210
source/firmware/md5.c
Normal file
@ -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 <stdint.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
24
source/firmware/md5.h
Normal file
24
source/firmware/md5.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef MD5_H
|
||||||
|
#define MD5_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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
|
||||||
@ -7,10 +7,12 @@ let cross-rv5 = import <nixpkgs> {
|
|||||||
libc = "newlib";
|
libc = "newlib";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
flags-file = "compile_flags.txt";
|
||||||
in
|
in
|
||||||
cross-rv5.mkShell {
|
cross-rv5.mkShell {
|
||||||
nativeBuildInputs = [ nixpkgs.gnumake nixpkgs.guile_3_0 ];
|
nativeBuildInputs = [ nixpkgs.gnumake nixpkgs.guile_3_0 ];
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
export NIX_SHELL_NAME="riscv"
|
export NIX_SHELL_NAME="riscv"
|
||||||
|
echo | riscv32-none-elf-gcc -E -Wp,-v - 2>&1 | grep "^ .*newlib" | sed 's/^ /-I/' > ${flags-file}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,5 +4,5 @@ set -e
|
|||||||
../scripts/register-gen.scm io.reg > io_reg.v
|
../scripts/register-gen.scm io.reg > io_reg.v
|
||||||
../scripts/register-gen.scm -c io.reg > io_reg.h
|
../scripts/register-gen.scm -c io.reg > io_reg.h
|
||||||
../scripts/register-gen.scm -t io.reg > io_reg.txt
|
../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 0x10000+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 -f > bus_mux.sby
|
||||||
|
|||||||
@ -9,6 +9,30 @@
|
|||||||
(info "Control register")
|
(info "Control register")
|
||||||
(bits 1 "stop" w (reset #b0)))
|
(bits 1 "stop" w (reset #b0)))
|
||||||
|
|
||||||
|
(reg "data_addr"
|
||||||
|
(info "Data block address")
|
||||||
|
(bits 32 "addr" r))
|
||||||
|
|
||||||
|
(reg "data_len"
|
||||||
|
(info "Data block length")
|
||||||
|
(bits 32 "len" r))
|
||||||
|
|
||||||
|
(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
|
(reg "console" read-notify
|
||||||
(info "Virtual console port")
|
(info "Virtual console port")
|
||||||
(bits 8 "data" rw (info "Read/write char from/to console"))
|
(bits 8 "data" rw (info "Read/write char from/to console"))
|
||||||
|
|||||||
@ -7,8 +7,38 @@
|
|||||||
#define IO_REG_CTRL (*(volatile uint32_t*)(IO_REG_BASE + 0x00000000))
|
#define IO_REG_CTRL (*(volatile uint32_t*)(IO_REG_BASE + 0x00000000))
|
||||||
#define IO_REG_CTRL_STOP (1 << 0)
|
#define IO_REG_CTRL_STOP (1 << 0)
|
||||||
|
|
||||||
|
/* -- Register 'DATA_ADDR' -- */
|
||||||
|
#define IO_REG_DATA_ADDR (*(volatile uint32_t*)(IO_REG_BASE + 0x00000004))
|
||||||
|
#define IO_REG_DATA_ADDR_ADDR__MASK 0xffffffff
|
||||||
|
#define IO_REG_DATA_ADDR_ADDR__SHIFT 0
|
||||||
|
|
||||||
|
/* -- Register 'DATA_LEN' -- */
|
||||||
|
#define IO_REG_DATA_LEN (*(volatile uint32_t*)(IO_REG_BASE + 0x00000008))
|
||||||
|
#define IO_REG_DATA_LEN_LEN__MASK 0xffffffff
|
||||||
|
#define IO_REG_DATA_LEN_LEN__SHIFT 0
|
||||||
|
|
||||||
|
/* -- Register 'MD5_OUT0' -- */
|
||||||
|
#define IO_REG_MD5_OUT0 (*(volatile uint32_t*)(IO_REG_BASE + 0x0000000c))
|
||||||
|
#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 + 0x00000010))
|
||||||
|
#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 + 0x00000014))
|
||||||
|
#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 + 0x00000018))
|
||||||
|
#define IO_REG_MD5_OUT3_DATA__MASK 0xffffffff
|
||||||
|
#define IO_REG_MD5_OUT3_DATA__SHIFT 0
|
||||||
|
|
||||||
/* -- Register 'CONSOLE' -- */
|
/* -- Register 'CONSOLE' -- */
|
||||||
#define IO_REG_CONSOLE (*(volatile uint32_t*)(IO_REG_BASE + 0x00000004))
|
#define IO_REG_CONSOLE (*(volatile uint32_t*)(IO_REG_BASE + 0x0000001c))
|
||||||
#define IO_REG_CONSOLE_DATA__MASK 0x000000ff
|
#define IO_REG_CONSOLE_DATA__MASK 0x000000ff
|
||||||
#define IO_REG_CONSOLE_DATA__SHIFT 0
|
#define IO_REG_CONSOLE_DATA__SHIFT 0
|
||||||
#define IO_REG_CONSOLE_SEND (1 << 8)
|
#define IO_REG_CONSOLE_SEND (1 << 8)
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
Register map of IO_REG (base: 0x1000000)
|
Register map of IO_REG (base: 0x1000000)
|
||||||
========================================
|
========================================
|
||||||
|
|
||||||
| Offset | Name | Description |
|
| Offset | Name | Description |
|
||||||
|------------+---------+----------------------|
|
|------------+-----------+-------------------------|
|
||||||
| 0x00000000 | CTRL | Control register |
|
| 0x00000000 | CTRL | Control register |
|
||||||
| 0x00000004 | CONSOLE | Virtual console port |
|
| 0x00000004 | DATA_ADDR | Data block address |
|
||||||
|
| 0x00000008 | DATA_LEN | Data block length |
|
||||||
|
| 0x0000000c | MD5_OUT0 | Bytes 0..3 of MD5 sum |
|
||||||
|
| 0x00000010 | MD5_OUT1 | Bytes 4..7 of MD5 sum |
|
||||||
|
| 0x00000014 | MD5_OUT2 | Bytes 8..11 of MD5 sum |
|
||||||
|
| 0x00000018 | MD5_OUT3 | Bytes 12..15 of MD5 sum |
|
||||||
|
| 0x0000001c | CONSOLE | Virtual console port |
|
||||||
|
|
||||||
|
|
||||||
CTRL Register (0x00000000)
|
CTRL Register (0x00000000)
|
||||||
@ -17,7 +23,67 @@ CTRL Register (0x00000000)
|
|||||||
| 0 | STOP | WO | 0 | |
|
| 0 | STOP | WO | 0 | |
|
||||||
|
|
||||||
|
|
||||||
CONSOLE Register (0x00000004)
|
DATA_ADDR Register (0x00000004)
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Data block address
|
||||||
|
|
||||||
|
| Bits | Name | Mode | Reset | Description |
|
||||||
|
|------+------+------+-------+-------------|
|
||||||
|
| 31:0 | ADDR | RO | 0 | |
|
||||||
|
|
||||||
|
|
||||||
|
DATA_LEN Register (0x00000008)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Data block length
|
||||||
|
|
||||||
|
| Bits | Name | Mode | Reset | Description |
|
||||||
|
|------+------+------+-------+-------------|
|
||||||
|
| 31:0 | LEN | RO | 0 | |
|
||||||
|
|
||||||
|
|
||||||
|
MD5_OUT0 Register (0x0000000c)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Bytes 0..3 of MD5 sum
|
||||||
|
|
||||||
|
| Bits | Name | Mode | Reset | Description |
|
||||||
|
|------+------+------+-------+-------------|
|
||||||
|
| 31:0 | DATA | WO | 0 | |
|
||||||
|
|
||||||
|
|
||||||
|
MD5_OUT1 Register (0x00000010)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Bytes 4..7 of MD5 sum
|
||||||
|
|
||||||
|
| Bits | Name | Mode | Reset | Description |
|
||||||
|
|------+------+------+-------+-------------|
|
||||||
|
| 31:0 | DATA | WO | 0 | |
|
||||||
|
|
||||||
|
|
||||||
|
MD5_OUT2 Register (0x00000014)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Bytes 8..11 of MD5 sum
|
||||||
|
|
||||||
|
| Bits | Name | Mode | Reset | Description |
|
||||||
|
|------+------+------+-------+-------------|
|
||||||
|
| 31:0 | DATA | WO | 0 | |
|
||||||
|
|
||||||
|
|
||||||
|
MD5_OUT3 Register (0x00000018)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Bytes 12..15 of MD5 sum
|
||||||
|
|
||||||
|
| Bits | Name | Mode | Reset | Description |
|
||||||
|
|------+------+------+-------+-------------|
|
||||||
|
| 31:0 | DATA | WO | 0 | |
|
||||||
|
|
||||||
|
|
||||||
|
CONSOLE Register (0x0000001c)
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
Virtual console port
|
Virtual console port
|
||||||
|
|||||||
152
source/io_reg.v
152
source/io_reg.v
@ -17,6 +17,24 @@ module io_reg
|
|||||||
/* ---- 'ctrl' ---- */
|
/* ---- 'ctrl' ---- */
|
||||||
output wire o_ctrl_stop,
|
output wire o_ctrl_stop,
|
||||||
|
|
||||||
|
/* ---- 'data_addr' ---- */
|
||||||
|
input wire [31:0] i_data_addr_addr,
|
||||||
|
|
||||||
|
/* ---- 'data_len' ---- */
|
||||||
|
input wire [31:0] i_data_len_len,
|
||||||
|
|
||||||
|
/* ---- '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' ---- */
|
/* ---- 'console' ---- */
|
||||||
output wire o_console__rnotify,
|
output wire o_console__rnotify,
|
||||||
input wire [7:0] i_console_data,
|
input wire [7:0] i_console_data,
|
||||||
@ -28,13 +46,53 @@ module io_reg
|
|||||||
|
|
||||||
/* ---- Address decoder ---- */
|
/* ---- Address decoder ---- */
|
||||||
wire ctrl_select;
|
wire ctrl_select;
|
||||||
|
wire data_addr_select;
|
||||||
|
wire data_len_select;
|
||||||
|
wire md5_out0_select;
|
||||||
|
wire md5_out1_select;
|
||||||
|
wire md5_out2_select;
|
||||||
|
wire md5_out3_select;
|
||||||
wire console_select;
|
wire console_select;
|
||||||
|
|
||||||
assign ctrl_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 data_addr_select =
|
||||||
|
i_addr[2] == 1'b1 &&
|
||||||
|
i_addr[3] == 1'b0 &&
|
||||||
|
i_addr[4] == 1'b0;
|
||||||
|
|
||||||
|
assign data_len_select =
|
||||||
|
i_addr[2] == 1'b0 &&
|
||||||
|
i_addr[3] == 1'b1 &&
|
||||||
|
i_addr[4] == 1'b0;
|
||||||
|
|
||||||
|
assign md5_out0_select =
|
||||||
|
i_addr[2] == 1'b1 &&
|
||||||
|
i_addr[3] == 1'b1 &&
|
||||||
|
i_addr[4] == 1'b0;
|
||||||
|
|
||||||
|
assign md5_out1_select =
|
||||||
|
i_addr[2] == 1'b0 &&
|
||||||
|
i_addr[3] == 1'b0 &&
|
||||||
|
i_addr[4] == 1'b1;
|
||||||
|
|
||||||
|
assign md5_out2_select =
|
||||||
|
i_addr[2] == 1'b1 &&
|
||||||
|
i_addr[3] == 1'b0 &&
|
||||||
|
i_addr[4] == 1'b1;
|
||||||
|
|
||||||
|
assign md5_out3_select =
|
||||||
|
i_addr[2] == 1'b0 &&
|
||||||
|
i_addr[3] == 1'b1 &&
|
||||||
|
i_addr[4] == 1'b1;
|
||||||
|
|
||||||
assign console_select =
|
assign console_select =
|
||||||
i_addr[2] == 1'b1;
|
i_addr[2] == 1'b1 &&
|
||||||
|
i_addr[3] == 1'b1 &&
|
||||||
|
i_addr[4] == 1'b1;
|
||||||
|
|
||||||
|
|
||||||
/* ---- 'ctrl' ---- */
|
/* ---- 'ctrl' ---- */
|
||||||
@ -50,6 +108,70 @@ module io_reg
|
|||||||
end
|
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' ---- */
|
/* ---- 'console' ---- */
|
||||||
reg [7:0] console_data;
|
reg [7:0] console_data;
|
||||||
assign o_console_data = console_data;
|
assign o_console_data = console_data;
|
||||||
@ -77,16 +199,42 @@ module io_reg
|
|||||||
|
|
||||||
/* ---- Read multiplexer ---- */
|
/* ---- Read multiplexer ---- */
|
||||||
reg [31:0] data_ctrl;
|
reg [31:0] data_ctrl;
|
||||||
|
reg [31:0] data_data_addr;
|
||||||
|
reg [31:0] data_data_len;
|
||||||
|
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;
|
reg [31:0] data_console;
|
||||||
|
|
||||||
assign o_data =
|
assign o_data =
|
||||||
data_ctrl |
|
data_ctrl |
|
||||||
|
data_data_addr |
|
||||||
|
data_data_len |
|
||||||
|
data_md5_out0 |
|
||||||
|
data_md5_out1 |
|
||||||
|
data_md5_out2 |
|
||||||
|
data_md5_out3 |
|
||||||
data_console;
|
data_console;
|
||||||
|
|
||||||
always @(*) begin
|
always @(*) begin
|
||||||
data_ctrl = 32'd0;
|
data_ctrl = 32'd0;
|
||||||
|
data_data_addr = 32'd0;
|
||||||
|
data_data_len = 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;
|
data_console = 32'd0;
|
||||||
|
|
||||||
|
if (data_addr_select) begin
|
||||||
|
data_data_addr[31:0] = i_data_addr_addr;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (data_len_select) begin
|
||||||
|
data_data_len[31:0] = i_data_len_len;
|
||||||
|
end
|
||||||
|
|
||||||
if (console_select) begin
|
if (console_select) begin
|
||||||
data_console[7:0] = i_console_data;
|
data_console[7:0] = i_console_data;
|
||||||
data_console[8] = i_console_send;
|
data_console[8] = i_console_send;
|
||||||
|
|||||||
228
source/md5calculator.sv
Normal file
228
source/md5calculator.sv
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
`timescale 1ps/1ps
|
||||||
|
|
||||||
|
module md5calculator
|
||||||
|
(input clock,
|
||||||
|
input reset,
|
||||||
|
output done,
|
||||||
|
input [31:0] md5_data_addr,
|
||||||
|
input [31:0] md5_data_len,
|
||||||
|
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_data_addr_addr(md5_data_addr),
|
||||||
|
.i_data_len_len(md5_data_len),
|
||||||
|
.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
|
||||||
@ -2,4 +2,5 @@
|
|||||||
../source/io_reg.v
|
../source/io_reg.v
|
||||||
../source/picorv32_tcm.sv
|
../source/picorv32_tcm.sv
|
||||||
../source/picorv32.v
|
../source/picorv32.v
|
||||||
|
../source/md5calculator.sv
|
||||||
../source/testbench.sv
|
../source/testbench.sv
|
||||||
|
|||||||
@ -1,204 +1,57 @@
|
|||||||
`timescale 1ps/1ps
|
`timescale 1ps/1ps
|
||||||
|
|
||||||
module testbench (input clock);
|
module testbench #(parameter CPU_COUNT = 1024)
|
||||||
parameter MEM_ADDR_WIDTH = 16;
|
(input clock);
|
||||||
|
|
||||||
logic reset = 1'b1;
|
localparam DATA_ADDR = 32'h00010000;
|
||||||
|
localparam DATA_LEN = 1024;
|
||||||
|
|
||||||
/* verilator lint_off UNUSED */
|
logic [31:0] data_len;
|
||||||
logic cpu_mem_valid;
|
logic [CPU_COUNT-1:0] done_all;
|
||||||
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
|
for (genvar ncpu = 0; ncpu < CPU_COUNT; ncpu = ncpu + 1) begin : cpus
|
||||||
logic cpu_mem_la_read;
|
localparam logic [31:0] MD5IN = ncpu;
|
||||||
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
|
logic done;
|
||||||
picorv32 #(.ENABLE_COUNTERS(0), // = 1,
|
logic reset;
|
||||||
.ENABLE_COUNTERS64(0), // = 1,
|
logic [127:0] md5;
|
||||||
.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
|
assign done_all[ncpu] = done;
|
||||||
.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
|
md5calculator cpu
|
||||||
.mem_la_read(cpu_mem_la_read), // output
|
(.clock, .reset, .done,
|
||||||
.mem_la_write(cpu_mem_la_write), // output
|
.md5_data_addr(DATA_ADDR),
|
||||||
.mem_la_addr(cpu_mem_la_addr), // output [31:0]
|
.md5_data_len(data_len),
|
||||||
.mem_la_wdata(cpu_mem_la_wdata), // output reg [31:0]
|
.md5(md5));
|
||||||
.mem_la_wstrb(cpu_mem_la_wstrb), // output reg [ 3:0]
|
|
||||||
|
|
||||||
// Unused
|
initial
|
||||||
/* verilator lint_off PINCONNECTEMPTY */
|
for (int n = 0; n < (2 ** (cpu.rom.ADDR_WIDTH-2)); n += 1)
|
||||||
.pcpi_valid(), // output reg
|
cpu.rom.ram[n] = ncpu;
|
||||||
.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
|
initial
|
||||||
// Slaves address ranges:
|
if(!$value$plusargs("dlen=%d", data_len))
|
||||||
// 0 - 0x00000000-0x0000ffff
|
data_len = DATA_LEN;
|
||||||
// 1 - 0x01000000-0x01000fff
|
|
||||||
|
|
||||||
// i_slave_rdata bits:
|
initial begin
|
||||||
// 0: i_slave_rdata[31:0]
|
reset = 1'b1;
|
||||||
// 1: i_slave_rdata[63:32]
|
repeat($urandom % 5 + 2) @(posedge clock);
|
||||||
|
reset = 1'b0;
|
||||||
|
@(posedge clock);
|
||||||
|
|
||||||
logic [31:0] rdata_ram;
|
while(!done) @(posedge clock);
|
||||||
logic [31:0] rdata_reg;
|
$display("MD5(0x%x) = %x", MD5IN, md5);
|
||||||
logic valid_ram;
|
end
|
||||||
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;
|
|
||||||
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
|
// Wait for complete
|
||||||
initial begin
|
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);
|
@(posedge clock);
|
||||||
|
|
||||||
|
$display("--- BENCH DONE ---");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
iverilog -g2012 -o top -f ../source/sources.f top.sv
|
. ../scripts/sim_vars.sh
|
||||||
|
|
||||||
|
iverilog -g2012 -o top -Ptop.CPU_COUNT=$CPU_COUNT -f $FFILE top.sv
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
vvp -n ./top
|
. ../scripts/sim_vars.sh
|
||||||
|
|
||||||
|
vvp -N ./top +dlen=$BLOCK_SIZE
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
`timescale 1ps/1ps
|
`timescale 1ps/1ps
|
||||||
|
|
||||||
module top;
|
module top #(parameter CPU_COUNT = 1024);
|
||||||
logic clock = 1'b0;
|
logic clock = 1'b0;
|
||||||
initial forever #(10ns/2) clock = ~clock;
|
initial forever #(10ns/2) clock = ~clock;
|
||||||
testbench testbench (clock);
|
testbench #(CPU_COUNT) testbench (clock);
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
. ../scripts/sim_vars.sh
|
||||||
|
|
||||||
rm -rf testbench
|
rm -rf testbench
|
||||||
vlog -sv -work testbench -vopt -f ../source/sources.f top.sv
|
vlog -sv -work testbench -vopt $param -f $FFILE top.sv
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
vsim -c -batch -voptargs=+acc=npr -do "run -all" -quiet -lib testbench top
|
. ../scripts/sim_vars.sh
|
||||||
|
|
||||||
|
vsim -batch -voptargs=+acc=npr -do "run -all" -quiet +dlen=$BLOCK_SIZE -GCPU_COUNT=$CPU_COUNT -lib testbench top
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
`timescale 1ps/1ps
|
`timescale 1ps/1ps
|
||||||
|
|
||||||
module top;
|
module top #(parameter CPU_COUNT = 1024);
|
||||||
logic clock = 1'b0;
|
logic clock = 1'b0;
|
||||||
initial forever #(10ns/2) clock = ~clock;
|
initial forever #(10ns/2) clock = ~clock;
|
||||||
testbench testbench (clock);
|
testbench #(CPU_COUNT) testbench (clock);
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@ -3,10 +3,12 @@ TOP_MODULE = testbench
|
|||||||
SOURCES = top.cpp clock_generator.cpp
|
SOURCES = top.cpp clock_generator.cpp
|
||||||
FLAGS_FILE = ../source/sources.f
|
FLAGS_FILE = ../source/sources.f
|
||||||
INCLUDES =
|
INCLUDES =
|
||||||
|
PARAMS :=
|
||||||
|
THREADS := 1
|
||||||
|
|
||||||
FLAGS = -Wno-WIDTH -cc --top-module $(TOP_MODULE) +1800-2017ext+sv \
|
FLAGS = -Wno-WIDTH -cc --top-module $(TOP_MODULE) +1800-2017ext+sv \
|
||||||
--timing --Mdir $(TOP_MODULE) -o $(TOP_MODULE) -f $(FLAGS_FILE) \
|
--timing --Mdir $(TOP_MODULE) -o $(TOP_MODULE) -f $(FLAGS_FILE) \
|
||||||
--timescale "1ps/1ps" --threads 1
|
$(PARAMS) --timescale "1ps/1ps" --threads $(THREADS) -j 0
|
||||||
|
|
||||||
# FLAGS += --trace
|
# FLAGS += --trace
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
. ../scripts/sim_vars.sh
|
||||||
|
|
||||||
make clean
|
make clean
|
||||||
make
|
make OPT_FAST="-Os -march=native" VM_PARALLEL_BUILDS=0 PARAMS="-GCPU_COUNT=$CPU_COUNT" THREADS=$THREADS
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
./testbench/testbench
|
. ../scripts/sim_vars.sh
|
||||||
|
|
||||||
|
./testbench/testbench +dlen=$BLOCK_SIZE
|
||||||
|
|||||||
1
test-xcelium/.dir-locals.el
Normal file
1
test-xcelium/.dir-locals.el
Normal file
@ -0,0 +1 @@
|
|||||||
|
((verilog-mode . ((flycheck-verilator-include-path . ("../source")))))
|
||||||
@ -1,7 +1,11 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
. ../scripts/sim_vars.sh
|
||||||
|
|
||||||
rm -rf xcelium.d
|
rm -rf xcelium.d
|
||||||
|
|
||||||
xmvlog -sv -f ../source/sources.f top.sv
|
## WARNING: defparam is not tested
|
||||||
xmelab -timescale 1ps/1ps top
|
|
||||||
|
xmvlog -sv -f $FFILE top.sv
|
||||||
|
xmelab -timescale 1ps/1ps -defparam top.CPU_COUNT=$CPU_COUNT top
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
xmsim -status top
|
. ../scripts/sim_vars.sh
|
||||||
|
|
||||||
|
xmsim -status top +dlen=$BLOCK_SIZE
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
`timescale 1ps/1ps
|
`timescale 1ps/1ps
|
||||||
|
|
||||||
module top;
|
module top #(parameter CPU_COUNT = 1024);
|
||||||
logic clock = 1'b0;
|
logic clock = 1'b0;
|
||||||
initial forever #(10ns/2) clock = ~clock;
|
initial forever #(10ns/2) clock = ~clock;
|
||||||
testbench testbench (clock);
|
testbench #(CPU_COUNT) testbench (clock);
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
2
test-xsim/.gitignore
vendored
2
test-xsim/.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
webtalk*
|
webtalk*
|
||||||
xsim.*
|
xsim*
|
||||||
xelab.*
|
xelab.*
|
||||||
xvlog.*
|
xvlog.*
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
FFILE=../source/sources.f
|
. ../scripts/sim_vars.sh
|
||||||
|
|
||||||
SOURCES=$(cat $FFILE | sed -ze 's/\n/ /g')
|
SOURCES=$(cat $FFILE | sed -ze 's/\n/ /g')
|
||||||
|
|
||||||
rm -rf xsim.dir
|
rm -rf xsim.dir
|
||||||
@ -10,4 +11,4 @@ rm -rf xvlog.* xelab.* xsim.*
|
|||||||
rm -rf top.wdb
|
rm -rf top.wdb
|
||||||
|
|
||||||
xvlog -work work --sv top.sv $SOURCES
|
xvlog -work work --sv top.sv $SOURCES
|
||||||
xelab --O3 -L work top
|
xelab --O3 --generic_top "CPU_COUNT=$CPU_COUNT" -L work top
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#vsim -c -batch -voptargs=+acc=npr -do "run -all" -quiet -lib testbench top
|
. ../scripts/sim_vars.sh
|
||||||
xsim top --runall
|
|
||||||
|
xsim top -testplusarg dlen=$BLOCK_SIZE --runall
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
`timescale 1ps/1ps
|
`timescale 1ps/1ps
|
||||||
|
|
||||||
module top;
|
module top #(parameter CPU_COUNT = 1024);
|
||||||
logic clock = 1'b0;
|
logic clock = 1'b0;
|
||||||
initial forever #(10ns/2) clock = ~clock;
|
initial forever #(10ns/2) clock = ~clock;
|
||||||
testbench testbench (clock);
|
testbench #(CPU_COUNT) testbench (clock);
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user