From 5c2b519abada806b66a1a4da77268a63eee88f89 Mon Sep 17 00:00:00 2001 From: Julio Nunes Avelar Date: Thu, 21 Nov 2024 16:39:06 -0300 Subject: [PATCH] Escrevendo README --- README.md | 209 +++++++++++++- README.pt.md | 364 +++++++++++++++++++++++++ config_generator.py | 32 ++- docs/conexao-processorci.drawio.png | Bin 0 -> 30392 bytes logs/darkriscv_1732212431.9015656.json | 167 ++++++++++++ logs/darkriscv_1732212457.7304223.json | 155 +++++++++++ 6 files changed, 917 insertions(+), 10 deletions(-) create mode 100644 README.pt.md create mode 100644 docs/conexao-processorci.drawio.png create mode 100644 logs/darkriscv_1732212431.9015656.json create mode 100644 logs/darkriscv_1732212457.7304223.json diff --git a/README.md b/README.md index 2cd31d3..6fff444 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,210 @@ # ProcessorCI -[![Pylint](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/pylint.yml/badge.svg)](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/pylint.yml) +[![Pylint](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/pylint.yml/badge.svg)](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/pylint.yml) +[![Python Code Format Check](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/blue.yml/badge.svg)](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/blue.yml) -[![Python Code Format Check](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/blue.yml/badge.svg)](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/blue.yml) +- **Não fala Inglês? [clique aqui](https://github.com/JN513/Risco-5/blob/main/README_pt.md)** + +Welcome to ProcessorCI! + +**ProcessorCI** is a project aimed at modernizing processor verification by integrating established verification techniques, continuous integration, and FPGA usage. + +## About this Module + +This repository contains utility scripts to configure processors, perform synthesis, load onto FPGAs, and other tasks related to ProcessorCI. + +## Getting Started + +### Installation + +1. **Clone the Repository** +Clone the repository to your local development environment: + +```bash +git clone https://github.com/LSC-Unicamp/processor-ci.git +cd processor-ci +``` + +2. **Set up a Virtual Environment and Install Dependencies** + +```bash +python3 -m venv env +. env/bin/activate +pip install -r requirements.txt +``` + +**Note**: Every time you use the project, activate the virtual environment with: + +```bash +. env/bin/activate +``` + +### Adding a New Processor + +The process to add a processor consists of three steps: + +1. Generate the configuration file (`config.json`). +2. Establish the connections for Verilog modules. +3. Integrate the pipeline file into Jenkins. + +#### 1. Generating Configurations + +To generate the Jenkins pipeline, fill out a JSON file with the processor's characteristics and add a new entry to `config.json`. Example: + +```json +"darkriscv": { + "name": "darkriscv", + "folder": "darkriscv", + "sim_files": [], + "files": ["rtl/darkriscv.v"], + "include_dirs": ["rtl"], + "repository": "https://github.com/darklife/darkriscv", + "top_module": "darkriscv", + "extra_flags": [], + "language_version": "2005" +} +``` + +To simplify this, the script `config_generator.py` can generate an initial configuration: + +```bash +python3 config_generator.py -u PROCESSOR_URL -c +``` + +This command will clone the repository, list the files, and add a new entry to `config.json`. You can change the configuration file path using the `-p` flag. To disable AI-based models, use the `-n` flag. + +After generation, review the configuration to ensure its correctness. + +#### 2. Establishing Connections + +The script will create a Verilog file corresponding to the processor. Edit this file to connect the processor's main module to the ProcessorCI's top module. If you manually filled out `config.json`, create a file based on the template: + +```bash +cp rtl/template.v rtl/.v +``` + +Example connection: + +```verilog +Controller #( + ... +) Controller( + ... + .clk_core (clk_core), + .reset_core(reset_core), + + .core_memory_response (core_memory_response), + .core_read_memory (memory_read), + .core_write_memory (memory_write), + .core_address_memory (address), + .core_write_data_memory(core_write_data), + .core_read_data_memory (core_read_data), + + //sync memory bus + .core_read_data_memory_sync (), + .core_memory_read_response_sync (), + .core_memory_write_response_sync(), + + // Data memory + .core_memory_response_data (), + .core_read_memory_data (1'b0), + .core_write_memory_data (1'b0), + .core_address_memory_data (32'h00000000), + .core_write_data_memory_data(32'h00000000), + .core_read_data_memory_data () +); +Core #( + .BOOT_ADDRESS(32'h00000000) +) Core( + .clk (clk_core), + .reset (reset_core), + .memory_response(core_memory_response), + .memory_read (memory_read), + .memory_write (memory_write), + .write_data (core_write_data), + .read_data (core_read_data), + .address (address) +); +``` + +More details are available in the [Controller documentation](https://lsc-unicamp.github.io/processor-ci-controller/). + +#### 3. Integrating with Jenkins + +After configuration, create a new item in Jenkins and copy the generated pipeline into it. Currently, there is no automated integration with the official Jenkins. If you want to integrate a new processor, open an *Issue* with the name, URL, and configuration. + +### Usage + +After configuring and integrating the processor into the infrastructure, you can interact with it using the project's scripts. The main interactions involve synthesis and loading onto various FPGAs. An example usage: + +```bash +cd processor_repository/ +# Perform synthesis +python3 /path_to_script/main.py -c /path_to_config/config.json -p risc-v -b digilent_nexys4_ddr +# Perform loading +python3 /path_to_script/main.py -c /path_to_config/config.json -p risc-v -b digilent_nexys4_ddr -l +``` + +- `-c /path_to_config/config.json`: Path to the processor configuration file. +- `-p risc-v`: Name of the processor to be synthesized. +- `-b digilent_nexys4_ddr`: Target FPGA for synthesis and loading. +- `-l`: Load the design onto the FPGA after synthesis. + +## Usage Options + +The ProcessorCI scripts offer various options configurable via flags. Below are the main flags and functionalities: + +### Available Flags in the Configuration Script + +- `-c, --generate-config`: Generate initial processor configurations from the repository URL. + +Example: + +```bash +python3 config_generator.py -c -u PROCESSOR_URL +``` + +Details: + +- Clones the processor repository. +- Analyzes repository files to identify modules and testbenches. +- Generates a JSON file with processor configurations. +- Optionally adds the generated configuration to the central file (`config.json`) using the `-a` flag. + +### Examples of Main Script Usage + +1. **Configure a processor for a specific board:** + +```bash +python3 script.py -c config.json -p processor_name -b board_name +``` + +2. **Define a custom path for toolchains:** + +```bash +python3 script.py -c config.json -p processor_name -b board_name -t /custom/toolchain/path +``` + +3. **Load the bitstream onto the FPGA after the build:** + +```bash +python3 script.py -c config.json -p processor_name -b board_name -l +``` + +**Requirements:** + +- A valid JSON configuration file containing data about processors and boards. +- Ensure the toolchain path and board configurations are correctly set in your environment. + +## Questions and Suggestions + +The official documentation is available at: [processorci.ic.unicamp.br](https://processorci.ic.unicamp.br/). +Questions and suggestions can be submitted in the Issues section on GitHub. Contributions are welcome, and all Pull Requests will be reviewed and merged when possible. + +## Contributing to the Project + +**Contributions**: If you wish to contribute improvements, see the [CONTRIBUTING.md](./CONTRIBUTING.md) file. + +## License + +This project is licensed under the [MIT License](./LICENSE), granting full freedom of use. \ No newline at end of file diff --git a/README.pt.md b/README.pt.md new file mode 100644 index 0000000..2c6b799 --- /dev/null +++ b/README.pt.md @@ -0,0 +1,364 @@ +# ProcessorCI + +[![Pylint](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/pylint.yml/badge.svg)](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/pylint.yml) +[![Python Code Format Check](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/blue.yml/badge.svg)](https://github.com/LSC-Unicamp/processor-ci/actions/workflows/blue.yml) + +Bem-vindo ao ProcessorCI! + +O **ProcessorCI** é um projeto que visa modernizar o processo de verificação de processadores, integrando técnicas consolidadas de verificação, integração contínua e uso de FPGAs. + +## Sobre este módulo + +Este repositório contém scripts utilitários para configurar processadores, realizar síntese, carregar em FPGAs, entre outras funções relacionadas ao ProcessorCI. + +## Iniciando + +### Instalação + +1. **Clone o repositório** +Clone o repositório para o seu ambiente de desenvolvimento local. + +```bash +git clone https://github.com/LSC-Unicamp/processor-ci.git +cd processor-ci +``` + +2. **Configure um ambiente virtual e instale as dependências** + +```bash +python3 -m venv env +. env/bin/activate +pip install -r requirements.txt +``` + +**Obs**: Sempre que for utilizar o projeto, é necessário ativar o ambiente virtual com: + +```bash +. env/bin/activate +``` + +### Adicionando um novo processador + +O processo para adicionar um processador consiste em três etapas: + +1. Gerar o arquivo de configuração (`config.json`). +2. Realizar a ligação dos módulos em Verilog. +3. Integrar o arquivo de pipeline ao Jenkins. + +#### 1. Gerando as configurações + +Para gerar o pipeline do Jenkins, preencha um arquivo `json` com as características do processador e adicione uma nova entrada ao `config.json`. Exemplo: + +```json +"darkriscv": { + "name": "darkriscv", + "folder": "darkriscv", + "sim_files": [], + "files": ["rtl/darkriscv.v"], + "include_dirs": ["rtl"], + "repository": "https://github.com/darklife/darkriscv", + "top_module": "darkriscv", + "extra_flags": [], + "language_version": "2005" +} +``` + +Para facilitar, o script `config_generator.py` pode gerar uma configuração inicial: + +```bash +python3 config_generator.py -u URL_DO_PROCESSADOR -c +``` + +Esse comando clonará o repositório, listará os arquivos e adicionará uma nova entrada no `config.json`. É possível alterar o caminho do arquivo de configuração usando a flag `-p`. Para desativar o uso de modelos baseados em IA, use a flag `-n`. + +Após a geração, revise a configuração para garantir que esteja correta. + +#### 2. Realizando a ligação + +O script criará um arquivo Verilog correspondente ao processador. Edite este arquivo para conectar o módulo principal do processador ao top module do ProcessorCI. Caso tenha preenchido manualmente o `config.json`, crie um arquivo baseado no template: + +```bash +cp rtl/template.v rtl/.v +``` + +Exemplo de ligação: + +```verilog +Controller #( + ... +) Controller( + ... + .clk_core (clk_core), + .reset_core(reset_core), + + .core_memory_response (core_memory_response), + .core_read_memory (memory_read), + .core_write_memory (memory_write), + .core_address_memory (address), + .core_write_data_memory(core_write_data), + .core_read_data_memory (core_read_data), + + //sync memory bus + .core_read_data_memory_sync (), + .core_memory_read_response_sync (), + .core_memory_write_response_sync(), + + // Data memory + .core_memory_response_data (), + .core_read_memory_data (1'b0), + .core_write_memory_data (1'b0), + .core_address_memory_data (32'h00000000), + .core_write_data_memory_data(32'h00000000), + .core_read_data_memory_data () +); +Core #( + .BOOT_ADDRESS(32'h00000000) +) Core( + .clk (clk_core), + .reset (reset_core), + .memory_response(core_memory_response), + .memory_read (memory_read), + .memory_write (memory_write), + .write_data (core_write_data), + .read_data (core_read_data), + .address (address) +); +``` + +Mais detalhes na [documentação do Controller](https://lsc-unicamp.github.io/processor-ci-controller/). + +#### 3. Integrando ao Jenkins + +Após configurar, crie um novo item no Jenkins e copie o pipeline gerado para ele. Atualmente, não há integração automática com o Jenkins oficial. Caso deseje integrar um novo processador, abra uma *Issue* com o nome, URL e configuração. + +### Utilização + +Após configurar e integrar o processador à infraestrutura, é possível interagir com ele utilizando os scripts do projeto. As interações principais consistem na realização de síntese e carregamento (load) para diferentes FPGAs. Um exemplo de utilização seria: + +```bash +cd processor_repository/ +# Realiza a síntese +python3 /path_to_script/main.py -c /path_to_config/config.json -p Risco-5 -b digilent_nexys4_ddr +# Realiza o carregamento (load) +python3 /path_to_script/main.py -c /path_to_config/config.json -p Risco-5 -b digilent_nexys4_ddr -l +``` + +- `-c /path_to_config/config.json`: Caminho para o arquivo de configuração do processador. +- `-p Risco-5`: Nome do processador a ser sintetizado. +- `-b digilent_nexys4_ddr`: FPGA de destino para síntese e carregamento. +- `-l`: Realiza o carregamento do design na FPGA após a síntese. + +## Opções de Utilização + +Os scripts do ProcessorCI possuem diversas opções configuráveis por meio de flags. Abaixo estão descritas as principais flags e funcionalidades: + +### Flags Disponíveis no script de configuração + +- `-c`, `--generate-config` +**Descrição:** Gera as configurações iniciais de um processador a partir da URL de seu repositório. + +**Exemplo de uso:** + +```bash +python3 config_generator.py -c -u URL_DO_PROCESSADOR +``` + +**Detalhes:** + +- Clona o repositório do processador. +- Analisa os arquivos do repositório para identificar módulos e testbenches. +- Gera um arquivo JSON com as configurações do processador. +- Pode adicionar a configuração gerada ao arquivo central (`config.json`) utilizando a flag `-a`. + +- `-u`, `--processor-url` + +**Descrição:** Especifica a URL do repositório do processador que será clonado. + +**Exemplo de uso:** + +```bash +python3 config_generator.py -c -u https://github.com/example/example-processor.git +``` + +- `-j`, `--generate-all-jenkinsfiles` + +**Descrição:** Gera arquivos Jenkinsfile para todos os processadores listados no arquivo de configuração central. + +**Exemplo de uso:** + +```bash +python3 config_generator.py -j +``` + +**Detalhes:** + +- Analisa o arquivo `config.json`. +- Cria um Jenkinsfile específico para cada processador suportado. + +- `-g`, `--plot-graph` + +**Descrição:** Gera gráficos de dependência dos módulos do processador. + +**Exemplo de uso:** + +```bash +python3 config_generator.py -c -u URL_DO_PROCESSADOR -g +``` + +- `-a`, `--add-config` + +**Descrição:** Adiciona a configuração gerada ao arquivo de configuração central (`config.json`). + +**Exemplo de uso:** + +```bash +python3 config_generator.py -c -u URL_DO_PROCESSADOR -a +``` + +- `-p`, `--path-config` + +**Descrição:** Define o caminho para o arquivo de configuração central. O padrão é `config.json`. + +**Exemplo de uso:** + +```bash +python3 config_generator.py -c -u URL_DO_PROCESSADOR -p /caminho/para/config.json +``` + +- `-n`, `--no-llama` + +**Descrição:** Desativa o uso do modelo *llama* para identificação automática do top module e outros parâmetros. + +**Exemplo de uso:** + +```bash +python3 config_generator.py -c -u URL_DO_PROCESSADOR -n +``` + +### Exemplos de Uso do script de configuração + +1. **Gerar uma configuração inicial para um processador:** + +```bash +python3 config_generator.py -c -u https://github.com/example/example-processor.git +``` + +2. **Adicionar a configuração gerada ao arquivo `config.json`:** + +```bash +python3 config_generator.py -c -u https://github.com/example/example-processor.git -a +``` + +3. **Gerar gráficos de dependência dos módulos:** + +```bash +python3 config_generator.py -c -u https://github.com/example/example-processor.git -g +``` + +4. **Criar arquivos Jenkinsfile para todos os processadores configurados:** + +```bash +python3 config_generator.py -j +``` + +5. **Definir um caminho personalizado para o arquivo `config.json`:** + +```bash +python3 config_generator.py -c -u https://github.com/example/example-processor.git -p /caminho/personalizado/config.json +``` + +### Flags Disponíveis no Script Principal + +- `-c`, `--config` + +**Descrição:** Especifica o caminho para o arquivo de configuração no formato JSON. Este arquivo contém os detalhes sobre os processadores e placas disponíveis para configuração. + +**Exemplo de uso:** + +```bash +python3 script.py -c config.json +``` + +- `-p`, `--processor` + +**Descrição:** Especifica o nome do processador a ser utilizado. Este argumento é obrigatório. + +**Exemplo de uso:** + +```bash +python3 script.py -c config.json -p nome_do_processador +``` + +- `-b`, `--board` + +**Descrição:** Especifica o nome da placa FPGA a ser utilizada. Este argumento é obrigatório. + +**Exemplo de uso:** + +```bash +python3 script.py -c config.json -p nome_do_processador -b nome_da_placa +``` + +- `-t`, `--toolchain` + +**Descrição:** Especifica o caminho para o diretório das toolchains. Se não fornecido, o caminho padrão é `/eda`. + +**Exemplo de uso:** + +```bash +python3 script.py -c config.json -p nome_do_processador -b nome_da_placa -t /caminho/para/toolchain +``` + +- `-l`, `--load` + +**Descrição:** Se especificado, o script irá carregar o bitstream gerado na FPGA após a construção. + +**Exemplo de uso:** + +```bash +python3 script.py -c config.json -p nome_do_processador -b nome_da_placa -l +``` + +### Exemplos de Uso + +1. **Configurar um processador para uma placa específica:** + +```bash +python3 script.py -c config.json -p nome_do_processador -b nome_da_placa +``` + +2. **Definir um caminho personalizado para as toolchains:** + +```bash +python3 script.py -c config.json -p nome_do_processador -b nome_da_placa -t /caminho/personalizado/toolchain +``` + +3. **Carregar o bitstream na FPGA após a construção:** + +```bash +python3 script.py -c config.json -p nome_do_processador -b nome_da_placa -l +``` + +4. **Usar o caminho padrão das toolchains (`/eda`):** + +```bash +python3 script.py -c config.json -p nome_do_processador -b nome_da_placa +``` + +**Requisitos:** + +- Um arquivo de configuração JSON válido é necessário, contendo os dados dos processadores e das placas. +- Certifique-se de que o caminho da toolchain e as configurações da placa estejam corretamente configurados no seu ambiente. + +## Dúvidas e sugestões + +A documentação oficial está disponível em: [processorci.ic.unicamp.br](https://processorci.ic.unicamp.br/). +Dúvidas e sugestões podem ser enviadas na seção de Issues no GitHub. Contribuições são bem-vindas, e todos os Pull Requests serão revisados e mesclados sempre que possível. + +## Contribuindo com o projeto + +**Contribuições**: Se você deseja contribuir com melhorias, veja como no arquivo [CONTRIBUTING.md](./CONTRIBUTING.md). + +## Licença + +Este projeto é licenciado sob a licença [MIT](./LICENSE), que garante total liberdade para uso. diff --git a/config_generator.py b/config_generator.py index 84dbac0..e6a40ed 100644 --- a/config_generator.py +++ b/config_generator.py @@ -141,7 +141,11 @@ def copy_hardware_template(repo_name: str) -> None: def generate_processor_config( - url: str, add_config: bool, plot_graph: bool, config_file_path: str + url: str, + add_config: bool, + plot_graph: bool, + config_file_path: str, + no_llama: bool, ) -> None: """ Generates a processor configuration by cloning a repository, analyzing its files, @@ -152,6 +156,7 @@ def generate_processor_config( add_config (bool): Whether to add the generated configuration to the config file. plot_graph (bool): Whether to plot the module dependency graphs. config_file_path (str): Path to the configuration file. + no_llama (bool): Whether to use OLLAMA to identify the top module. Returns: None @@ -197,12 +202,16 @@ def generate_processor_config( # Construir os grafos direto e inverso module_graph, module_graph_inverse = build_module_graph(files, modules) - filtered_files = get_filtered_files_list( - non_tb_files, tb_files, modules, module_graph, repo_name - ) - top_module = get_top_module( - non_tb_files, tb_files, modules, module_graph, repo_name - ) + filtered_files = non_tb_files + top_module = '' + + if not no_llama: + filtered_files = get_filtered_files_list( + non_tb_files, tb_files, modules, module_graph, repo_name + ) + top_module = get_top_module( + non_tb_files, tb_files, modules, module_graph, repo_name + ) language_version = '2005' @@ -218,7 +227,7 @@ def generate_processor_config( 'folder': repo_name, 'sim_files': tb_files, 'files': filtered_files, - 'include_dirs': include_dirs, + 'include_dirs': list(include_dirs), 'repository': url, 'top_module': top_module, 'extra_flags': [], @@ -350,6 +359,12 @@ def main() -> None: type=str, help='URL of the processor repository', ) + parser.add_argument( + '-n', + '--no-llama', + action='store_true', + help='Não utilizar o OLLAMA para identificar o módulo principal', + ) args = parser.parse_args() @@ -362,6 +377,7 @@ def main() -> None: args.add_config, args.plot_graph, args.path_config, + args.no_llama, ) if args.generate_all_jenkinsfiles: diff --git a/docs/conexao-processorci.drawio.png b/docs/conexao-processorci.drawio.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c115c84028daa5afcebff1775a1010da47ed38 GIT binary patch literal 30392 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 O1hTepz}1+0Q~nQ4#zcGo literal 0 HcmV?d00001 diff --git a/logs/darkriscv_1732212431.9015656.json b/logs/darkriscv_1732212431.9015656.json new file mode 100644 index 0000000..2a41830 --- /dev/null +++ b/logs/darkriscv_1732212431.9015656.json @@ -0,0 +1,167 @@ +{ + "name": "darkriscv", + "folder": "darkriscv", + "sim_files": [ + "sim/darksimv.v" + ], + "files": [ + "boards/colorlighti5/pll_ref_25MHz.v", + "boards/colorlighti9/pll_ref_25MHz.v", + "boards/ice40_breakout_hx8k/pll.v", + "boards/ulx3s/pll_ref_25MHz.v", + "rtl/darkbridge.v", + "rtl/darkcache.v", + "rtl/darkio.v", + "rtl/darkpll.v", + "rtl/darkram.v", + "rtl/darkriscv.v", + "rtl/darksocv.v", + "rtl/darkuart.v", + "rtl/lib/mt48lc16m16a2_ctrl.v" + ], + "include_dirs": [], + "repository": "https://github.com/darklife/darkriscv", + "top_module": "", + "extra_flags": [], + "language_version": "2005", + "modules": [ + { + "module": "pll_ref_25MHz", + "file": "boards/colorlighti5/pll_ref_25MHz.v" + }, + { + "module": "pll_ref_25MHz", + "file": "boards/colorlighti9/pll_ref_25MHz.v" + }, + { + "module": "was", + "file": "boards/ice40_breakout_hx8k/pll.v" + }, + { + "module": "pll", + "file": "boards/ice40_breakout_hx8k/pll.v" + }, + { + "module": "pll_ref_25MHz", + "file": "boards/ulx3s/pll_ref_25MHz.v" + }, + { + "module": "darkbridge", + "file": "rtl/darkbridge.v" + }, + { + "module": "darkcache", + "file": "rtl/darkcache.v" + }, + { + "module": "darkio", + "file": "rtl/darkio.v" + }, + { + "module": "darkpll", + "file": "rtl/darkpll.v" + }, + { + "module": "darkram", + "file": "rtl/darkram.v" + }, + { + "module": "darkriscv", + "file": "rtl/darkriscv.v" + }, + { + "module": "darksocv", + "file": "rtl/darksocv.v" + }, + { + "module": "darkuart", + "file": "rtl/darkuart.v" + }, + { + "module": "mt48lc16m16a2_ctrl", + "file": "rtl/lib/mt48lc16m16a2_ctrl.v" + }, + { + "module": "darksimv", + "file": "sim/darksimv.v" + } + ], + "module_graph": { + "pll_ref_25MHz": [ + "darkpll" + ], + "was": [], + "pll": [], + "darkbridge": [ + "darksocv" + ], + "darkcache": [ + "darkbridge", + "darkbridge" + ], + "darkio": [ + "darksocv" + ], + "darkpll": [ + "darksocv" + ], + "darkram": [ + "darksocv" + ], + "darkriscv": [ + "darkbridge" + ], + "darksocv": [], + "darkuart": [ + "darkio" + ], + "mt48lc16m16a2_ctrl": [ + "darksocv" + ], + "darksimv": [] + }, + "module_graph_inverse": { + "pll_ref_25MHz": [], + "was": [], + "pll": [], + "darkbridge": [ + "darkriscv", + "darkcache", + "darkcache" + ], + "darkcache": [], + "darkio": [ + "darkuart" + ], + "darkpll": [ + "pll_ref_25MHz" + ], + "darkram": [], + "darkriscv": [], + "darksocv": [ + "darkpll", + "darkbridge", + "darkram", + "darkio", + "mt48lc16m16a2_ctrl" + ], + "darkuart": [], + "mt48lc16m16a2_ctrl": [], + "darksimv": [] + }, + "non_tb_files": [ + "boards/colorlighti5/pll_ref_25MHz.v", + "boards/colorlighti9/pll_ref_25MHz.v", + "boards/ice40_breakout_hx8k/pll.v", + "boards/ulx3s/pll_ref_25MHz.v", + "rtl/darkbridge.v", + "rtl/darkcache.v", + "rtl/darkio.v", + "rtl/darkpll.v", + "rtl/darkram.v", + "rtl/darkriscv.v", + "rtl/darksocv.v", + "rtl/darkuart.v", + "rtl/lib/mt48lc16m16a2_ctrl.v" + ] +} \ No newline at end of file diff --git a/logs/darkriscv_1732212457.7304223.json b/logs/darkriscv_1732212457.7304223.json new file mode 100644 index 0000000..24f1fb4 --- /dev/null +++ b/logs/darkriscv_1732212457.7304223.json @@ -0,0 +1,155 @@ +{ + "name": "darkriscv", + "folder": "darkriscv", + "sim_files": [ + "sim/darksimv.v" + ], + "files": [ + "rtl/darkriscv.v" + ], + "include_dirs": [], + "repository": "https://github.com/darklife/darkriscv", + "top_module": "darkriscv", + "extra_flags": [], + "language_version": "2005", + "modules": [ + { + "module": "pll_ref_25MHz", + "file": "boards/colorlighti5/pll_ref_25MHz.v" + }, + { + "module": "pll_ref_25MHz", + "file": "boards/colorlighti9/pll_ref_25MHz.v" + }, + { + "module": "was", + "file": "boards/ice40_breakout_hx8k/pll.v" + }, + { + "module": "pll", + "file": "boards/ice40_breakout_hx8k/pll.v" + }, + { + "module": "pll_ref_25MHz", + "file": "boards/ulx3s/pll_ref_25MHz.v" + }, + { + "module": "darkbridge", + "file": "rtl/darkbridge.v" + }, + { + "module": "darkcache", + "file": "rtl/darkcache.v" + }, + { + "module": "darkio", + "file": "rtl/darkio.v" + }, + { + "module": "darkpll", + "file": "rtl/darkpll.v" + }, + { + "module": "darkram", + "file": "rtl/darkram.v" + }, + { + "module": "darkriscv", + "file": "rtl/darkriscv.v" + }, + { + "module": "darksocv", + "file": "rtl/darksocv.v" + }, + { + "module": "darkuart", + "file": "rtl/darkuart.v" + }, + { + "module": "mt48lc16m16a2_ctrl", + "file": "rtl/lib/mt48lc16m16a2_ctrl.v" + }, + { + "module": "darksimv", + "file": "sim/darksimv.v" + } + ], + "module_graph": { + "pll_ref_25MHz": [ + "darkpll" + ], + "was": [], + "pll": [], + "darkbridge": [ + "darksocv" + ], + "darkcache": [ + "darkbridge", + "darkbridge" + ], + "darkio": [ + "darksocv" + ], + "darkpll": [ + "darksocv" + ], + "darkram": [ + "darksocv" + ], + "darkriscv": [ + "darkbridge" + ], + "darksocv": [], + "darkuart": [ + "darkio" + ], + "mt48lc16m16a2_ctrl": [ + "darksocv" + ], + "darksimv": [] + }, + "module_graph_inverse": { + "pll_ref_25MHz": [], + "was": [], + "pll": [], + "darkbridge": [ + "darkriscv", + "darkcache", + "darkcache" + ], + "darkcache": [], + "darkio": [ + "darkuart" + ], + "darkpll": [ + "pll_ref_25MHz" + ], + "darkram": [], + "darkriscv": [], + "darksocv": [ + "darkpll", + "darkbridge", + "darkram", + "darkio", + "mt48lc16m16a2_ctrl" + ], + "darkuart": [], + "mt48lc16m16a2_ctrl": [], + "darksimv": [] + }, + "non_tb_files": [ + "boards/colorlighti5/pll_ref_25MHz.v", + "boards/colorlighti9/pll_ref_25MHz.v", + "boards/ice40_breakout_hx8k/pll.v", + "boards/ulx3s/pll_ref_25MHz.v", + "rtl/darkbridge.v", + "rtl/darkcache.v", + "rtl/darkio.v", + "rtl/darkpll.v", + "rtl/darkram.v", + "rtl/darkriscv.v", + "rtl/darksocv.v", + "rtl/darkuart.v", + "rtl/lib/mt48lc16m16a2_ctrl.v" + ] +} \ No newline at end of file