Merge pull request #311 from efabless/cocotb

Cocotb - update cocotb scrip to fully support iverilog and update cocotb documentation
This commit is contained in:
Mohamed Shalan 2022-10-20 19:14:34 +02:00 committed by GitHub
commit bdc2667911
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 370 additions and 148 deletions

View File

@ -8,7 +8,7 @@ cc82a78753f5f5d0a1519bd81adbcff8a4296d91 verilog/rtl/__user_project_wrapper.v
2cc670e819a1cae69314242364118f5d4267737c verilog/rtl/caravan.v
06e92151b5928e3f28e30a5cde76f7dd6530ed91 verilog/rtl/caravan_netlists.v
a3d12a2d2d3596800bec47d1266dce2399a2fcc6 verilog/rtl/caravan_openframe.v
5bc67d2d75579d06ab0d0395e634a08f39e3474b verilog/rtl/caravel.v
b38b8911910265a96d8248095964a5ee8139820b verilog/rtl/caravel.v
2fe34f043edbe87c626e5616ad54f82c9ba067c2 verilog/rtl/caravel_clocking.v
625c9f974f1a3c9bd2eca5449a89a7bfb8f69fe8 verilog/rtl/caravel_logo.v
1bbaa93405d4cb51429eacea4da40014231b11ed verilog/rtl/caravel_motto.v

View File

@ -1,79 +0,0 @@
# SPDX-FileCopyrightText: 2020 Efabless Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
PWDD := $(shell pwd)
BLOCKS := $(shell basename $(PWDD))
# ---- Include Partitioned Makefiles ----
CONFIG = caravel_user_project
# TestName = temp_partial
# export COCOTB_ANSI_OUTPUT=0 # disable color in termianl
export GUI=1
export COCOTB_REDUCED_LOG_FMT=1
# Change this line if you want to use existing cocotb test modules:
# export PYTHONPATH := $(DESIGNS)/verilog/rtl/<your design python tests>
# export LIBPYTHON_LOC=$(cocotb-config --libpython)
#export VERILOG_PATH = ../../../
#export CARAVEL_PATH = ../../../../../caravel/verilog/
# include $(MCW_ROOT)/verilog/dv/make/env.makefile
# #export VERILOG_PATH = ../../../
# include $(MCW_ROOT)/verilog/dv/make/var.makefile
# include $(MCW_ROOT)/verilog/dv/make/cpu.makefile
# include $(MCW_ROOT)/verilog/dv/make/sim.makefile
TESTCASE=$(TestName)
MODULE=caravel_tests
$(info $$MODULE is [$(MODULE)])
cocotb:
rm -rf sim_build/
mkdir sim_build/
# change project_tb.v to match your testbench
#RTL
iverilog -Ttyp -DFUNCTIONAL -DSIM -DUSE_POWER_PINS -DUNIT_DELAY=#1 \
-DTESTNAME=\"$(TestName)\" -DTAG=\"$(RUNTAG)\" -DSIM=\"$(SIM)\" \
-f$(VERILOG_PATH)/includes/includes.rtl.caravel \
-o sim_build/sim.vvp $(CARAVEL_PATH)/rtl/__user_project_wrapper.v $(CARAVEL_PATH)/rtl/debug_regs.v caravel_top.sv
#GL
# iverilog -Ttyp -DFUNCTIONAL -DGL -DUSE_POWER_PINS -DUNIT_DELAY=#1 \
# -DTESTNAME=\"$(TestName)\" -DRUNTAG=\"$(RUNTAG)\" -DSIM=\"$(SIM)\" \
# -f$(VERILOG_PATH)/includes/includes.gl.caravel \
# -f$(USER_PROJECT_VERILOG)/includes/includes.gl.$(CONFIG) -o sim_build/sim.vvp caravel_top.sv
#CVC
# TESTCASE=$(TestName) MODULE=caravel_tests cvc64 +interp +acc+2 \
# +loadvpi=$(shell cocotb-config --lib-name-path vpi cvc):vlog_startup_routines_bootstrap\
# +change_port_type +maxerrors 1\
# +define+SIM +define+FUNCTIONAL +define+GL +define+USE_POWER_PINS +define+UNIT_DELAY=#0 \
# +define+TESTNAME=\"$(TestName)\" +define+RUNTAG=\"$(RUNTAG)\" +define+COCOTB_SIM=1\
# -f $(VERILOG_PATH)/includes/includes.gl+sdf.caravel \
# -f $(USER_PROJECT_VERILOG)/includes/includes.gl+sdf.$(CONFIG) -o sim_build/sim.vvp
# verilator --vpi --public-flat-rw --prefix Vtop \
# -LDFLAGS "-Wl,-rpath,$(cocotb-config --prefix)/cocotb/libs \
# -L$(cocotb-config --prefix)/cocotb/libs \
# -lcocotbvpi_verilator -lgpi -lcocotb -lgpilog -lcocotbutils" \
# $(cocotb-config --share)/lib/verilator/verilator.cpp\
# -y $(VERILOG_PATH)/includes/includes.rtl.caravel \
# -y $(USER_PROJECT_VERILOG)/includes/includes.rtl.$(CONFIG) --cc -o sim_build/sim.vvp caravel_top.sv
# change this line to choose the comma separated test cases and the name of your python test module
TESTCASE=$(TestName) MODULE=caravel_tests vvp -M $$(cocotb-config --prefix)/cocotb/libs -m libcocotbvpi_icarus sim_build/sim.vvp
! grep failure results.xml

View File

@ -12,15 +12,10 @@ Prerequisites
- Docker: [Linux](https://hub.docker.com/search?q=&type=edition&offering=community&operating_system=linux&utm_source=docker&utm_medium=webreferral&utm_campaign=dd-smartbutton&utm_location=header) || [Windows](https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe?utm_source=docker&utm_medium=webreferral&utm_campaign=dd-smartbutton&utm_location=header) || [Mac with Intel Chip](https://desktop.docker.com/mac/main/amd64/Docker.dmg?utm_source=docker&utm_medium=webreferral&utm_campaign=dd-smartbutton&utm_location=header) || [Mac with M1 Chip](https://desktop.docker.com/mac/main/arm64/Docker.dmg?utm_source=docker&utm_medium=webreferral&utm_campaign=dd-smartbutton&utm_location=header)
- Python 3.6+ with PIP
- cocotb
```
apt update && apt install python3 python3-pip
pip3 install cocotb
pip3 install cocotb_coverage
pip3 install coverage
pip3 install cocotb-bus
```
- ```docker pull efabless/dv:cocotb```
- iverilog or vcs
- export CARAVEL_ROOT= \<caravel repo root\>
- export MCW_ROOT= \<caravel_mgmt_soc_litex repo root\>
run a test
=============================
@ -29,48 +24,44 @@ run a test
```
-h, --help show this help message and exit
-regression REGRESSION, -r REGRESSION
name of regression can found in tests.json
-test TEST [TEST ...], -t TEST [TEST ...]
name of test if no --sim provided RTL will be run
<takes list as input>
-sim SIM [SIM ...] Simulation type to be run RTL,GL&GL_SDF provided only
when run -test <takes list as input>
-testlist TESTLIST, -tl TESTLIST
path of testlist to be run
-tag TAG provide tag of the run default would be regression
name and if no regression is provided would be
run_<random float>_<timestamp>_
-maxerr MAXERR max number of errors for every test before simulation
breaks default = 3
-vcs, -v use vcs as compiler if not used iverilog would be used
-cov, -c enable code coverage
-cov enable code coverage
-corner CORNER [CORNER ...], -c CORNER [CORNER ...]
Corner type in case of GL_SDF run has to be provided
-keep_pass_unzip Normally the waves and logs of passed tests would be
zipped. Using this option they wouldn't be zipped
```
Refer to [examples](doc/commands_example/README.md)
Tests
===============
Refer to [tests.json](tests.json) for tests list
Refer to [tests doc](doc/tests/README.md) for tests list
Directories names fixed for now
===============
>repo
>>caravel_mgmt_soc_litex/
>>caravel
>>>verilog
>>>>dv
>>>>cocotb
cocotb directory tree
===============
@ -90,3 +81,7 @@ cocotb directory tree
└── wb_models -> contains checkers and models for some caravel blocks
```
How to debug
===============
` TO BE ADDED`

View File

@ -26,6 +26,7 @@ from tests.bitbang.bitbang_tests import *
from tests.bitbang.bitbang_tests_cpu import *
from tests.housekeeping.housekeeping_regs.housekeeping_regs_tests import *
from tests.housekeeping.housekeeping_spi.user_pass_thru import *
from tests.housekeeping.housekeeping_spi.spi import *
from tests.housekeeping.general.pll import *
from tests.housekeeping.general.sys_ctrl import *
from tests.temp_partial_test.partial import *

View File

@ -0,0 +1,22 @@
# tests commands
## run one test in RTL
``` python3 verify_cocotb.py -t uart_tx -tag uart_tx_rtl ```
``` python3 verify_cocotb.py -t uart_tx -sim RTL -tag uart_tx_rtl ```
## run one test in GL
``` python3 verify_cocotb.py -t uart_tx -sim GL -tag uart_tx_gl ```
## run one test in more than 1 corner
``` python3 verify_cocotb.py -t uart_tx -sim RTL GL -tag uart_tx_rtl_gl ```
## run more than 1 test
``` python3 verify_cocotb.py -t uart_tx uart_rx -tag uart_tx_rx_rtl ```
``` python3 verify_cocotb.py -t uart_tx uart_rx -sim RTL GL -tag uart_tx_rx_rtl_gl ```
# Regressions commands
## running all RTl tests
``` python3 verify_cocotb.py -r r_rtl -tag all_rtl ```
## running all GL tests
``` python3 verify_cocotb.py -r r_gl -tag all_gl ```
# tests and regression
``` python3 verify_cocotb.py -r r_rtl -t uart_tx uart_rx -sim GL -tag all_rtl_and_uart_gl ```

View File

@ -0,0 +1,105 @@
# gpio
### gpio_all_i
```configure all gpios as mgmt input using automatic approach firmware and check them```
### gpio_all_i_user
```configure all gpios as user input using automatic approach firmware and check them```
### gpio_all_i_pu
```configure all gpios as mgmt input pull up using automatic approach firmware and check them```
### gpio_all_i_pu_user
```configure all gpios as user input pull up using automatic approach firmware and check them```
### gpio_all_i_pd
```configure all gpios as mgmt input pull down using automatic approach firmware and check them```
### gpio_all_i_pd_user
```configure all gpios as user input pull down using automatic approach firmware and check them```
### gpio_all_bidir_user
```configure all gpios as user bidir using automatic approach firmware and check them```
### gpio_all_o
```configure all gpios as mgmt output using automatic approach firmware and check them```
### gpio_all_o_user
```configure all gpios as user output using automatic approach firmware and check them```
### mgmt_gpio_out
```tests blinking of mgmt gpio bit as an output```
### mgmt_gpio_in
```tests blinking of mgmt gpio bit as an output```
### mgmt_gpio_bidir
```send random number of blinks through mgmt_gpio and expect to recieve the same number back ```
# housekeeping
### hk_disable
```check Housekeeping SPI disable register is working```
### hk_regs_rst_spi
```check reset value of house keeping registers by reading them trough the spi housekeeping```
### hk_regs_wr_wb_cpu
```bit bash test for housekeeping registers```
### hk_regs_wr_spi
```write then read(the written value) from random housekeeping registers through the SPI housekeeping```
### hk_regs_wr_wb
```write then read (the written value) from random housekeeping registers through the firmware but without using CPU, the SPI and system regs can't be read using firmware so the test only GPIO regs inside housekeeping ```
# uart
### uart_rx
```test uart reception```
### uart_loopback
```test uart in loopback mode input and output is shorted```
### uart_tx
```test uart transmit```
# irq
### IRQ_timer
```test timer0 interrupt```
### IRQ_external
```test external interrupt by mprj 7```
### IRQ_uart
```test timer0 interrupt```
# bitbang
### bitbang_cpu_all_i
``` configure gpio[0:37] as mgmt input using bitbang and check them```
### bitbang_spi_o
```Same as bitbang_cpu_all but configure the gpio using the SPI not the firmware```
### bitbang_spi_i
```Same as bitbang_cpu_all_i but configure the gpio using the SPI not the firmware```
### bitbang_cpu_all_o
```configure all gpios as mgmt output using bitbang and check them```
### bitbang_cpu_all_01
```shift all the register with 01```
### bitbang_cpu_all_10
```shift all the register with 10```
### bitbang_cpu_all_1100
```shift all the register with 1100```
### bitbang_cpu_all_0011
```shift all the register with 0011```
### bitbang_no_cpu_all_o
```test disable CPU and control the wishbone to configure gpio[4:37] as mgmt output using bitbang and check them```
### bitbang_no_cpu_all_i
```test disable CPU and control the wishbone to configure gpio[0:31] as mgmt input using bitbang and check them```
# timer
### timer0_oneshot
```check timer0 oneshot mode```
### timer0_periodic
```check timer0 periodic mode```
# general
### debug
```use caravel in debug mode and check reading and writing from dff2 RAM```
### clock_redirect
```check clock redirect is working as expected```
### mem_dff
```Memory stress for all space of dff```
### mem_dff2
```Memory stress for all space of dff2```
### helloWorld
```hello world test```
# housekeeping_spi
### spi_master_rd
```using SPI master for reading from external memory```
### user_pass_thru_rd
```use the housekeeping spi in user pass thru mode to read from external mem```
### spi_master_temp
```To be deleted```
### spi_rd_wr_nbyte
```try housekeeping spi Write and Read in n-byte mode ```
# la
### la
```check logic analyzer input and output enable```
# pll
### pll
```Check pll diffrent configuration```
# cpu
### cpu_stress
```stress the cpu with heavy processing```

View File

@ -0,0 +1,52 @@
#!/usr/bin/python3
import json
import os
from fnmatch import fnmatch
import collections
"""This script is for updating the README file with tests from test.json"""
with open('../../tests.json') as f:
tests_json = json.load(f)["Tests"]
tests = collections.defaultdict(lambda : collections.defaultdict()) #key is testname and value is list of sim types
for test,test_elements in tests_json.items():
if fnmatch(test,"_*"):
continue
elif fnmatch(test,"*bitbang*"):
tests["bitbang"][test] = test_elements["description"]
elif fnmatch(test,"*gpio*"):
tests["gpio"][test] = test_elements["description"]
elif fnmatch(test,"*hk*"):
tests["housekeeping"][test] = test_elements["description"]
elif fnmatch(test,"*spi*") or fnmatch(test,"*user_pass_thru*"):
tests["housekeeping_spi"][test] = test_elements["description"]
elif fnmatch(test,"*cpu*"):
tests["cpu"][test] = test_elements["description"]
elif fnmatch(test,"*irq*") or fnmatch(test,"*IRQ*"):
tests["irq"][test] = test_elements["description"]
elif fnmatch(test,"*timer*"):
tests["timer"][test] = test_elements["description"]
elif fnmatch(test,"*spi_master*"):
tests["spi_master"][test] = test_elements["description"]
elif fnmatch(test,"*uart*"):
tests["uart"][test] = test_elements["description"]
elif fnmatch(test,"*la*"):
tests["la"][test] = test_elements["description"]
elif fnmatch(test,"*pll*"):
tests["pll"][test] = test_elements["description"]
else:
tests["general"][test] = test_elements["description"]
with open("README.md", 'w') as file:
for key, value in tests.items():
file.write(f"# {key}\n")
for test,test_elements in value.items():
file.write(f"### {test} \n")
file.write(f"```{test_elements}``` \n")
for key, value in tests.items():
print(key)
print(value)

View File

@ -183,7 +183,7 @@
"RTL":["r_rtl","setup","nightly","weekly","tape_out"],
"GL":["r_gl","nightly","weekly","tape_out"],
"GL_SDF":["r_sdf","weekly","tape_out"],
"description":""}
"description":"use caravel in debug mode and check reading and writing from dff2 RAM"}
,"spi_master_rd" :{"level":0,
"SW":true,
"RTL":["r_rtl","setup","nightly","weekly","tape_out"],
@ -311,6 +311,12 @@
"GL":[],
"GL_SDF":[],
"description":"hello world test"}
,"spi_rd_wr_nbyte" :{"level":3,
"SW":false,
"RTL":[],
"GL":[],
"GL_SDF":[],
"description":"try housekeeping spi Write and Read in n-byte mode "}
}
}

View File

@ -0,0 +1,42 @@
import random
import cocotb
from cocotb.triggers import FallingEdge,RisingEdge,ClockCycles,Timer
import cocotb.log
from interfaces.cpu import RiskV
from interfaces.defsParser import Regs
from cocotb.result import TestSuccess
from tests.common_functions.test_functions import *
from tests.spi_master.SPI_VIP import read_mem ,SPI_VIP
from tests.housekeeping.housekeeping_spi.spi_access_functions import *
bit_time_ns = 0
reg = Regs()
@cocotb.test()
@repot_test
async def spi_rd_wr_nbyte(dut):
caravelEnv,clock = await test_configure(dut,timeout_cycles=14833)
cpu = RiskV(dut)
cpu.cpu_force_reset()
cpu.cpu_release_reset()
cocotb.log.info (f"[TEST] start spi_rd_wr_nbyte test")
nbytes_limits= 8
# writing to the random number(1 to 8) of bits after 0x1E (gpio_configure[4]) address avoid changing gpio 3
for j in range(3):
address = random.randint(0x26 , 0x67-nbytes_limits)
n_bytes = random.randint(1,nbytes_limits)
await write_reg_spi_nbytes(caravelEnv,address,[0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F],nbytes_limits)
await write_reg_spi_nbytes(caravelEnv,address,[0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0],n_bytes)
data = await read_reg_spi_nbytes(caravelEnv,address,nbytes_limits)
for i in range(nbytes_limits):
if i >= n_bytes:
if data[i] != 0x1F:
cocotb.log.error(f"[TEST] register {i} has returned value {data[i]} while it should return value 0x1F n_bytes = {n_bytes}")
else: cocotb.log.info(f"[TEST] successful read 0 from register {i} n_bytes = {n_bytes}")
else:
if data[i] != 0:
cocotb.log.error(f"[TEST] register number {i} has returned value {data[i]} > 0 while it should return value == 0 n_bytes = {n_bytes}")
else: cocotb.log.info(f"[TEST] successful read {data[i]} from register {i} n_bytes = {n_bytes}")
await ClockCycles(caravelEnv.clk,200)

View File

@ -16,6 +16,26 @@ async def read_reg_spi(caravelEnv,address):
await caravelEnv.disable_csb()
return data
async def write_reg_spi_nbytes(caravelEnv,address,data,n_bytes):
write_command = 0x2 << 6 | n_bytes << 3
print(f"command = {hex(write_command)}")
await caravelEnv.enable_csb()
await caravelEnv.hk_write_byte(write_command) # Write n byte command
await caravelEnv.hk_write_byte(address) # Address (register 19 = GPIO bit-bang control)
for byte in data:
await caravelEnv.hk_write_byte(byte) # Data = 0x01 (enable bit-bang mode)
await caravelEnv.disable_csb()
async def read_reg_spi_nbytes(caravelEnv,address,n_bytes):
data =[]
await caravelEnv.enable_csb()
await caravelEnv.hk_write_byte(0x40) # read stream command
await caravelEnv.hk_write_byte(address) # Address
for i in range(n_bytes):
data.append(await caravelEnv.hk_read_byte()) # Data = 0x01 (enable bit-bang mode)
await caravelEnv.disable_csb()
return data
async def reg_spi_user_pass_thru(caravelEnv,command,address):
await caravelEnv.enable_csb()

View File

@ -0,0 +1,10 @@
#include <defs.h>
#include <stub.c>
// Empty C code
void main()
{
print("adding a very very long delay because cpu produces X's when code finish and this break the simulation");
return;
}

View File

@ -1,4 +1,3 @@
from email.headerregistry import Address
import random
import cocotb
from cocotb.triggers import FallingEdge,RisingEdge,ClockCycles,Timer

View File

@ -5,14 +5,14 @@ import json
import sys
import os
from pathlib import Path
import json
from fnmatch import fnmatch
from datetime import datetime
import random
from pathlib import Path
import shutil
from subprocess import PIPE, run
import threading
import time
iverilog = True
vcs = False
@ -67,14 +67,21 @@ class RunTest:
self.sim_path = f"sim/{os.getenv('RUNTAG')}/{test_dir}/"
terminal_log=f"{self.sim_path}/fullTerminal.log"
test_log=f"{self.sim_path}/{self.test_name}.log"
self.full_terminal = open(test_log, "w")
self.test_log=open(test_log, "w")
self.full_file=f"{self.sim_path}/full.log"
self.full_terminal = open(self.full_file, "w")
def runTest(self):
self.full_test_name = f"{self.sim_type}-{self.test_name}"
if (self.sim_type=="GL_SDF"):
self.full_test_name = f"{self.sim_type}-{self.test_name}-{self.corner}"
os.environ["TESTFULLNAME"] = f"{self.full_test_name}"
if (iverilog):return self.runTest_iverilog()
elif(vcs): return self.runTest_vcs()
# iverilog function
def runTest_iverilog(self):
print(f"Start running test: {self.sim_type}-{self.test_name}")
CARAVEL_ROOT = os.getenv('CARAVEL_ROOT')
CARAVEL_VERILOG_PATH = os.getenv('CARAVEL_VERILOG_PATH')
MCW_ROOT = os.getenv('MCW_ROOT')
@ -86,12 +93,39 @@ class RunTest:
ERRORMAX = os.getenv('ERRORMAX')
PDK_ROOT = os.getenv('PDK_ROOT')
PDK = os.getenv('PDK')
env_vars = f"-e {CARAVEL_ROOT} -e CARAVEL_VERILOG_PATH={CARAVEL_VERILOG_PATH} -e MCW_ROOT={MCW_ROOT} -e VERILOG_PATH={VERILOG_PATH} -e CARAVEL_PATH={CARAVEL_PATH} -e USER_PROJECT_VERILOG={USER_PROJECT_VERILOG} -e FIRMWARE_PATH={FIRMWARE_PATH} -e RUNTAG={RUNTAG} -e ERRORMAX={ERRORMAX} -e PDK_ROOT={PDK_ROOT} -e PDK={PDK}"
print(f"Start running test: {self.sim_type}-{self.test_name}")
command = f"TestName={self.test_name} SIM={self.sim_type} make cocotb >> {self.full_terminal.name} "
os.system(f"docker run -it {env_vars} -v {os.getenv('CARAVEL_ROOT')}:{os.getenv('CARAVEL_ROOT')} -v {os.getenv('MCW_ROOT')}:{os.getenv('MCW_ROOT')} -v {os.getenv('PDK_ROOT')}:{os.getenv('PDK_ROOT')} efabless/dv:cocotb sh -c 'cd {self.cocotb_path} && {command}'")
self.passed = search_str(self.full_terminal.name,"Test passed with (0)criticals (0)errors")
TESTFULLNAME = os.getenv('TESTFULLNAME')
env_vars = f"-e {CARAVEL_ROOT} -e CARAVEL_VERILOG_PATH={CARAVEL_VERILOG_PATH} -e MCW_ROOT={MCW_ROOT} -e VERILOG_PATH={VERILOG_PATH} -e CARAVEL_PATH={CARAVEL_PATH} -e USER_PROJECT_VERILOG={USER_PROJECT_VERILOG} -e FIRMWARE_PATH={FIRMWARE_PATH} -e RUNTAG={RUNTAG} -e ERRORMAX={ERRORMAX} -e PDK_ROOT={PDK_ROOT} -e PDK={PDK} -e TESTFULLNAME={TESTFULLNAME}"
macros = f'-DFUNCTIONAL -DSIM=\\\"{self.sim_type}\\\" -DUSE_POWER_PINS -DUNIT_DELAY=#1 -DMAIN_PATH=\\\"{self.cocotb_path}\\\" -DIVERILOG -DTESTNAME=\\\"{self.test_name}\\\" -DTAG=\\\"{RUNTAG}\\\" '
if self.test_name == "la":
macros = f'{macros} -DLA_TESTING'
if self.test_name in ["gpio_all_o_user","gpio_all_i_user","gpio_all_i_pu_user","gpio_all_i_pd_user","gpio_all_bidir_user"]:
macros = f'{macros} -DGPIO_TESTING'
if(self.sim_type=="RTL"):
includes = f"-f {VERILOG_PATH}/includes/includes.rtl.caravel"
elif(self.sim_type=="GL"):
macros = f'{macros} -DGL'
includes = f"-f {VERILOG_PATH}/includes/includes.gl.caravel"
elif(self.sim_type=="GLSDF"):
print(f"iverilog can't run SDF for test {self.test_name} Please use anothor simulator like cvc" )
return
iverilog_command = (f"iverilog -Ttyp {macros} {includes} -o {self.sim_path}/sim.vvp"
f" {CARAVEL_PATH}/rtl/__user_project_wrapper.v {CARAVEL_PATH}/rtl/__user_project_gpio_example.v {CARAVEL_PATH}/rtl/__user_project_la_example.v caravel_top.sv"
f" && TESTCASE={self.test_name} MODULE=caravel_tests vvp -M $(cocotb-config --prefix)/cocotb/libs -m libcocotbvpi_icarus {self.sim_path}/sim.vvp")
docker_command = f"docker run -it {env_vars} -v {os.getenv('CARAVEL_ROOT')}:{os.getenv('CARAVEL_ROOT')} -v {os.getenv('MCW_ROOT')}:{os.getenv('MCW_ROOT')} -v {os.getenv('PDK_ROOT')}:{os.getenv('PDK_ROOT')} efabless/dv:cocotb sh -c 'cd {self.cocotb_path} && {iverilog_command}' >> {self.full_file}"
self.full_terminal = open(self.full_file, "a")
self.full_terminal.write(f"docker command for running iverilog and cocotb:\n% ")
self.full_terminal.write(os.path.expandvars(docker_command)+"\n")
self.full_terminal.close()
os.system(docker_command)
self.passed = search_str(self.test_log.name,"Test passed with (0)criticals (0)errors")
Path(f'{self.sim_path}/{self.passed}').touch()
if self.passed == "passed":
print(f"Test: {self.sim_type}-{self.test_name} passed")
else :
print(f"Test: {self.sim_type}-{self.test_name} Failed please check logs under {self.sim_path}")
# vcs function
def runTest_vcs(self):
@ -104,7 +138,6 @@ class RunTest:
dirs = f' {dirs} -f \\\"{VERILOG_PATH}/includes/rtl_caravel_vcs.list\\\" '
else:
dirs = f' {dirs} -f \\\"{VERILOG_PATH}/includes/gl_caravel_vcs.list\\\" '
full_test_name = f"{self.sim_type}-{self.test_name}"
macros = f'+define+FUNCTIONAL +define+USE_POWER_PINS +define+UNIT_DELAY=#1 +define+MAIN_PATH=\\\"{self.cocotb_path}\\\" +define+VCS '
if self.test_name == "la":
macros = f'{macros} +define+LA_TESTING'
@ -119,7 +152,6 @@ class RunTest:
# os.makedirs(f"annotation_logs",exist_ok=True)
dirs = f"{dirs} +incdir+\\\"{os.getenv('MCW_ROOT')}/verilog/\\\" "
# +incdir+\\\"{os.getenv('CARAVEL_ROOT')}/signoff/caravel/primetime-signoff/\\\"
full_test_name = f"{self.sim_type}-{self.test_name}-{self.corner}"
elif(self.sim_type=="GL"):
macros = f'{macros} +define+GL +define+SIM=GL'
elif (self.sim_type=="RTL"):
@ -132,11 +164,10 @@ class RunTest:
os.environ["TESTCASE"] = f"{self.test_name}"
os.environ["MODULE"] = f"caravel_tests"
os.environ["SIM"] = self.sim_type
os.environ["TESTFULLNAME"] = f"{full_test_name}"
os.system(f"vlogan -full64 -sverilog +error+30 caravel_top.sv {dirs} {macros} +define+TESTNAME=\\\"{self.test_name}\\\" +define+FTESTNAME=\\\"{full_test_name}\\\" +define+TAG=\\\"{os.getenv('RUNTAG')}\\\" -l {self.sim_path}/analysis.log -o {self.sim_path} ")
os.system(f"vlogan -full64 -sverilog +error+30 caravel_top.sv {dirs} {macros} +define+TESTNAME=\\\"{self.test_name}\\\" +define+FTESTNAME=\\\"{self.full_test_name}\\\" +define+TAG=\\\"{os.getenv('RUNTAG')}\\\" -l {self.sim_path}/analysis.log -o {self.sim_path} ")
os.system(f"vcs +lint=TFIPC-L {coverage_command} +error+30 -R -diag=sdf:verbose +sdfverbose +neg_tchk -debug_access -full64 -l {self.sim_path}/test.log caravel_top -Mdir={self.sim_path}/csrc -o {self.sim_path}/simv +vpi -P pli.tab -load $(cocotb-config --lib-name-path vpi vcs)")
self.passed = search_str(self.full_terminal.name,"Test passed with (0)criticals (0)errors")
self.passed = search_str(self.test_log.name,"Test passed with (0)criticals (0)errors")
Path(f'{self.sim_path}/{self.passed}').touch()
#delete wave when passed
if self.passed == "passed" and zip_waves:
@ -192,9 +223,11 @@ class RunTest:
sed_command = f"sed -ie 's/@10/@00/g' {hex_file}"
hex_gen_state = os.system(f"docker run -it -v {go_up(self.cocotb_path,4)}:{go_up(self.cocotb_path,4)} efabless/dv:latest sh -c 'cd {test_dir} && {elf_command} && {hex_command} && {sed_command} '")
self.full_terminal.write(os.path.expandvars(elf_command)+"\n"+"\n")
self.full_terminal.write(os.path.expandvars(hex_command)+"\n"+"\n")
self.full_terminal.write(os.path.expandvars(sed_command)+"\n"+"\n")
self.full_terminal.write("elf file generation command:\n% ")
self.full_terminal.write(os.path.expandvars(elf_command)+"\n")
self.full_terminal.write("hex file generation command:\n% ")
self.full_terminal.write(os.path.expandvars(hex_command)+"\n% ")
self.full_terminal.write(os.path.expandvars(sed_command)+"\n")
self.cd_cocotb()
self.full_terminal.close()
if hex_gen_state != 0 :
@ -307,30 +340,44 @@ class RunRegression:
self.unknown_tests +=1
def run_regression(self):
threads = list()
for test,sim_types in self.tests.items():
for sim_type,corners in sim_types.items(): # TODO: add multithreading or multiprocessing here
for corner,status in corners.items(): # TODO: add multithreading or multiprocessing here
start_time = datetime.now()
self.tests[test][sim_type][corner]["starttime"] = datetime.now().strftime("%H:%M:%S(%a)")
self.tests[test][sim_type][corner]["duration"] = "-"
self.tests[test][sim_type][corner]["status"] = "running"
self.update_reg_log()
test_run = RunTest(test,sim_type,corner)
self.tests[test][sim_type][corner]["status"] = "done"
self.tests[test][sim_type][corner]["endtime"] = datetime.now().strftime("%H:%M:%S(%a)")
self.tests[test][sim_type][corner]["duration"] = ("%.10s" % (datetime.now() - start_time))
self.tests[test][sim_type][corner]["pass"]= test_run.passed
if test_run.passed == "passed":
self.passed_tests +=1
elif test_run.passed == "failed":
self.failed_tests +=1
self.unknown_tests -=1
self.update_reg_log()
for corner,status in corners.items():
if iverilog: #threading
# x = threading.Thread(target=self.test_run_function,args=(test,sim_type,corner))
# threads.append(x)
# x.start()
# time.sleep(10)
self.test_run_function(test,sim_type,corner)
else:
self.test_run_function(test,sim_type,corner)
for index, thread in enumerate(threads):
thread.join()
if coverage:
self.generate_cov()
#TODO: add send mail here
def test_run_function(self,test,sim_type,corner):
start_time = datetime.now()
self.tests[test][sim_type][corner]["starttime"] = datetime.now().strftime("%H:%M:%S(%a)")
self.tests[test][sim_type][corner]["duration"] = "-"
self.tests[test][sim_type][corner]["status"] = "running"
self.update_reg_log()
test_run = RunTest(test,sim_type,corner,)
self.tests[test][sim_type][corner]["status"] = "done"
self.tests[test][sim_type][corner]["endtime"] = datetime.now().strftime("%H:%M:%S(%a)")
self.tests[test][sim_type][corner]["duration"] = ("%.10s" % (datetime.now() - start_time))
self.tests[test][sim_type][corner]["pass"]= test_run.passed
if test_run.passed == "passed":
self.passed_tests +=1
elif test_run.passed == "failed":
self.failed_tests +=1
self.unknown_tests -=1
self.update_reg_log()
def generate_cov(self):
os.chdir(f"{self.cocotb_path}/sim/{os.getenv('RUNTAG')}")
os.system(f"urg -dir RTL*/*.vdb -format both -show tests -report coverageRTL/")

View File

@ -244,6 +244,12 @@ module caravel (
wire por_l_buf;
wire porb_h_buf;
// SoC core
wire caravel_clk;
wire caravel_clk2;
wire caravel_rstn;
// top-level buffers
buff_flash_clkrst flash_clkrst_buffers (
`ifdef USE_POWER_PINS
@ -399,10 +405,6 @@ module caravel (
.mprj_analog_io(user_analog_io)
);
// SoC core
wire caravel_clk;
wire caravel_clk2;
wire caravel_rstn;
// Logic analyzer signals
wire [127:0] la_data_in_user; // From CPU to MPRJ