Skip to content

Commit

Permalink
[dv] Vplan flow preparation
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Velay <mvelay@lowrisc.org>
  • Loading branch information
martin-velay committed Sep 20, 2024
1 parent e5b2f14 commit d35f4ed
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 0 deletions.
26 changes: 26 additions & 0 deletions util/verification/csv2hjson.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python3
import sys
import csv
import hjson

# Check if the file to be converted has been defined
if len(sys.argv) > 1:
# Read the CSV file
csv_file = sys.argv[1]

with open(csv_file, mode='r', newline='', encoding='utf-8') as file:
csv_reader = csv.DictReader(file)
data = [row for row in csv_reader]

# Convert data into HJSON
hjson_data = hjson.dumps(data, indent=2)

# Write the HJSON file
with open('vplan_example_converted.hjson', mode='w', encoding='utf-8') as file:
file.write(hjson_data)

print("Conversion successfully completed")
else:
print("Error: please specify the CSV file path to be converted")
print(" eg.: ./csv2hjson.py dv/files/verif/my_vplan.csv")
exit
35 changes: 35 additions & 0 deletions util/verification/hjson2csv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
import sys
import csv
import hjson

# Check if the file to be converted has been defined
if len(sys.argv) > 1:
# Load data from the HJSON file
hjson_file = sys.argv[1]
with open(hjson_file, 'r', encoding='utf-8') as file:
data = hjson.load(file)

# Check that the data is a list of objects
if isinstance(data, list) and all(isinstance(item, dict) for item in data):
# Extract column headers from the keys of the first object
headers = data[0].keys()

# Create the CSV file
csv_file = 'vplan_example_converted.csv'
with open(csv_file, 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=headers)

# Write headers in the CSV
writer.writeheader()

# Write the data rows in the CSV
writer.writerows(data)

print("Conversion successfully completed")
else:
print("HJSON data is not in the expected format")
else:
print("Error: please specify the HJSON file path to be converted")
print(" eg.: ./hjson2csv.py dv/files/verif/my_vplan.hjson")
exit
25 changes: 25 additions & 0 deletions util/verification/mem_xyz_trace_req_test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# MEM_XYZ HW IP Technical Specification

[`mem_xyz`](https://reports.opentitan.org/hw/ip/mem_xyz/dv/latest/report.html):
![](https://dashboards.lowrisc.org/badges/dv/mem_xyz/test.svg)
![](https://dashboards.lowrisc.org/badges/dv/mem_xyz/passing.svg)
![](https://dashboards.lowrisc.org/badges/dv/mem_xyz/functional.svg)
![](https://dashboards.lowrisc.org/badges/dv/mem_xyz/code.svg)

# Overview

This document specifies MEM_XYZ hardware IP functionality. This module conforms to
the [OpenTitan guideline for peripheral device functionality.](../../../doc/contributing/hw/comportability/README.md)
See that document for integration overview within the broader OpenTitan top level system.


## Features

- Memory address space is...<!-- req_mem_xyz_162F -->
- It supports read and write commands<!-- req_mem_xyz_0882 -->
- All the address space is read and write accessible<!-- req_mem_xyz_24BE -->
- Address width is an RTL parameter among:
- 8<!-- req_mem_xyz_3A6A -->
- 16<!-- req_mem_xyz_3A4E -->
- 32<!-- req_mem_xyz_3637 -->
- Multiple modes are available: mode_a, mode_b and mode_c<!-- req_mem_xyz_10B7 -->
148 changes: 148 additions & 0 deletions util/verification/trace_req.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/usr/bin/env python3
import sys
import os
import hjson
import argparse
import re

def find_markdown_files(directory):
"""Recursively find all Markdown files in a directory, except in 'dv' directories."""
markdown_files = []

# Walk through directory and subdirectories
for root, dirs, files in os.walk(directory):
# Exclude 'dv' directories
dirs[:] = [d for d in dirs if d != 'dv']

# Find all .md files
for file in files:
if file.endswith('.md'):
markdown_files.append(os.path.join(root, file))

return markdown_files

def extract_tags_from_markdown(markdown_file, block_name):
"""Extract tags from the Markdown file using a regex pattern based on block_name."""
try:
with open(markdown_file, 'r') as md_file:
content = md_file.read()
except FileNotFoundError:
print(f"Error: The Markdown file '{markdown_file}' was not found.")
return set()

# Regex pattern to find tags in the form of 'req_<block_name>_xxxx' where xxxx is 4 hexadecimal digits
pattern = fr"req_{block_name}_[0-9a-fA-F]{{4}}"
tags = re.findall(pattern, content)
return set(tags) # Return unique tags as a set

def extract_tags_from_hjson(hjson_file, block_name):
"""Extract tags from the HJSON file using a regex pattern based on block_name."""
try:
with open(hjson_file, 'r') as hjson_file:
hjson_content = hjson.load(hjson_file)
except FileNotFoundError:
print(f"Error: The HJSON file '{hjson_file}' was not found.")
sys.exit(1)

# Convert the HJSON file to string and search for tags
content = str(hjson_content)

# Regex pattern to find tags in the form of 'req_<block_name>_xxxx' where xxxx is 4 hexadecimal digits
pattern = fr"req_{block_name}_[0-9a-fA-F]{{4}}"
tags = re.findall(pattern, content)
return set(tags) # Return unique tags as a set

def compare_tags(directory, hjson_file, block_name):
"""Compare tags from Markdown files in a directory with those in the HJSON file."""

# Find all .md files in the directory (except 'dv')
markdown_files = find_markdown_files(directory)

if not markdown_files:
print(f"No Markdown files found in directory '{directory}'")
return

# Display found Markdown files
print("The following Markdown files have been found and will be analyzed:")
for md_file in markdown_files:
print(f" {md_file}")

print() # Blank line before continuing

# Collect tags from all Markdown files, and map tags to files
markdown_tags = set()
tags_in_files = {} # To store which tags are in which files

for md_file in markdown_files:
file_tags = extract_tags_from_markdown(md_file, block_name)
markdown_tags.update(file_tags)

# Map tags to the file they were found in
for tag in file_tags:
if tag not in tags_in_files:
tags_in_files[tag] = []
tags_in_files[tag].append(md_file)

# Extract tags from the HJSON file
hjson_tags = extract_tags_from_hjson(hjson_file, block_name)

# Count number of tags
num_md_tags = len(markdown_tags)
num_matching_tags = len(markdown_tags.intersection(hjson_tags))

# Find tags that are missing in the HJSON file
missing_in_hjson = markdown_tags - hjson_tags

# Find tags that are in HJSON but not in Markdown
missing_in_markdown = hjson_tags - markdown_tags

# Print summary
print(f"Total number of tags found in Markdown files: {num_md_tags}")
print(f"Number of tags found in both Markdown and HJSON: {num_matching_tags}")

if missing_in_hjson:
print("\nTags found in Markdown but missing in HJSON:")
for tag in missing_in_hjson:
print(f" {tag} (found in {', '.join(tags_in_files[tag])})")
else:
print("All tags in the Markdown files are present in the HJSON file.")

print(f"\n")
print(f"Total number of tags found in HJSON file: {len(hjson_tags)}")
print(f"Number of tags found in HJSON but missing in Markdown: {len(missing_in_markdown)}")

if missing_in_markdown:
print("Tags found in HJSON but missing in Markdown:")
for tag in missing_in_markdown:
print(f" {tag}")

def main():
# Set up argument parser
parser = argparse.ArgumentParser(
description="Compare 'req_<block_name>_xxxx' tags between Markdown specifications and the HJSON verification plan.")
parser.add_argument(
'block_name',
type=str,
help='The block name to look for in the tag format "req_<block_name>_xxxx".'
)
parser.add_argument(
'directory',
type=str,
help='The path to the root directory of the block/IP. '
'The sub-directories will be automatically explored except the "dv" folder.'
'Eg.: hw/ip/block_name'
)
parser.add_argument(
'hjson_file',
type=str,
help='The path to the HJSON file.'
)

# Parse arguments
args = parser.parse_args()

# Call the compare function with the provided directory, HJSON file, and block name
compare_tags(args.directory, args.hjson_file, args.block_name)

if __name__ == '__main__':
main()
22 changes: 22 additions & 0 deletions util/verification/vplan_example_original.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Name,ID,Coverage Result,Description,Depth,Node Kind,Metric Kind,Item,Owner,Priority,Milestone,Weight,Issue,Comment
mem_xyz,,,A synchronous memory with a parameterizable address width and data width.,0,dut,,,,,,,,
testlist,,,Testlist,1,title,,,,,,,,
main_test,req_mem_xyz_1324,,Main test,2,coverage,testcase,tc_my_test,Michel,1,V1,5,#15926,
bad_addr,req_mem_xyz_0E55,,Bad address,2,coverage,testcase,tc_addr_err,Andrew,2,V3,3,#15927,
fcov,,,Feature coverage,1,title,,,,,,,,
addr_space,req_mem_xyz_162F,,All address space,2,coverage,functional,cp_addr,Francesca,1,V1,2,#14562,
rw_cmd,req_mem_xyz_0882,,Read and write commands,2,coverage,functional,cp_cmd,Michel,1,V1,2,#14562,
rw_addr_space,req_mem_xyz_24BE,,Read and write to all address space,2,coverage,functional,cp_addr_x_cp_cmd,Francesca,1,V1,2,#14562,
mem_full,req_mem_xyz_0F0A,,Reach memory full,2,coverage,functional,cp_full,Andrew,2,V2,3,#14562,This cannot be tested if block_abc is not ready
concurrent_rw,req_mem_xyz_2730,,Read and write simultaneously,2,coverage,assertion,assert_rd_wr,Andrew,3,V3,2,#11487,
addr_width_8bits,req_mem_xyz_364E,,Address 8 bits width,2,coverage,formal,fpv_addr_8bits,Andrew,1,V2,1,#2287,
addr_width_16bits,req_mem_xyz_3A6A,,Address 16 bits width,2,coverage,formal,fpv_addr_16bits,Andrew,1,V2,1,#2287,
addr_width_32bits,req_mem_xyz_3A4E,,Address 32 bits width,2,coverage,formal,fpv_addr_32bits,Andrew,3,V2,1,#2287,
data_width_8bits,req_mem_xyz_3637,,Data width 8 bits,2,coverage,formal,fpv_data_8width,Andrew,1,V2,1,#2287,
instanciate_fifo_common_lib,req_mem_xyz_9A4D,,"Uses the FIFO from the common library, test de la virgule, c'est OK ?",2,vplan,,vplan_fifo,,1,V1,10,#2145,Incorporate the sub-module verification plan
...,...,,...,...,...,...,...,...,...,,,...,
mem_depth,req_mem_xyz_12A4,,Memory depth,2,coverage,formal,fpv_mem_depth,Andrew,1,,1,#2287,
code_cov,,,Code coverage,1,title,,,,,V3,40%,,
code_cov_statement,req_mem_xyz_47D7,,Statement,2,coverage,code,s_cov(memory_xyz),,3,,,#7894,Need to run UNR before
code_cov_fsm,req_mem_xyz_2047,,FSM,2,coverage,code,f_cov(memory_xyz),,3,,,#7894,
code_cov_branch,req_mem_xyz_309C,,Branch...,2,coverage,code,b_cov(memory_xyz),,3,,,#7894,

0 comments on commit d35f4ed

Please sign in to comment.