ibex icon indicating copy to clipboard operation
ibex copied to clipboard

How to use Ibex with mainline fusesoc

Open shareefj opened this issue 10 months ago • 2 comments

Hi there,

You seem to still be using a custom Fusesoc version that expects a different GAPI structure. The ot branch you recommend using is quite a way behind mainline Fusesoc so what are your plans for merging changes and/or pulling the latest changes into your fork?

Can you expand on the main differences? Is it just related to your generators or are there additional features?

What would be the workaround for anyone needing to use the latest features of Fusesoc? Can the Ibex source be generated and exported using something like the OT vendoring scripts? Just thinking how I can work around this.

shareefj avatar Jan 03 '25 15:01 shareefj

Ergh, and you're on an ancient version of Edalize so I can't use that. Any pointers to how I can import the RTL source and ignore your Fusesoc flow would be great.

ghost avatar Jan 03 '25 16:01 ghost

I've deleted my previous post here and added a new export script. This clones the Ibex repo, runs your version of Fusesoc to export the RTL, and then post processes the RTL to uniquify it. In our case we followed the OT naming convensions so have a bunch of prim_ files that clash.

The following Core file enables usage of this exported code base in any other project. I might think about how to combine these two steps at some point if you think it worthwhile.

#!/usr/bin/env python3

import os
import sys
import shutil
import tempfile
import subprocess
import fileinput
import re
import argparse
import logging

logger = logging.getLogger(__name__)


def run_command(cmd, cwd=None):
    try:
        subprocess.run(cmd, cwd=cwd, check=True)
    except subprocess.CalledProcessError as e:
        logger.info(f"Error running command {' '.join(cmd)}: \n{e}")
        sys.exit(1)


def setup_venv(ibex_dir):
    run_command([sys.executable, "-m", "venv", "venv"], cwd=ibex_dir)
    venv_python = os.path.join(ibex_dir, "venv", "bin", "python")
    run_command([venv_python, "-m", "pip", "install", "-U", "pip", "wheel"], cwd=ibex_dir)
    run_command([venv_python, "-m", "pip", "install", "-r", "python-requirements.txt"], cwd=ibex_dir)
    return venv_python


def find_files(build_dir):
    files = []
    for root, _, filenames in os.walk(build_dir):
        for file in filenames:
            if file.endswith(('.sv', '.svh', '.vlt')):
                files.append(os.path.join(root, file))
    return files


def process_file(src, dest_dir, prefix):
    with open(src, 'r') as f:
        content = f.read()

    filename = os.path.basename(src)
    if filename.startswith('prim_') or re.search(r'(module|package)\s+prim_[a-zA-Z0-9_]+', content):
        filename = prefix + filename

    dest = os.path.join(dest_dir, filename)
    shutil.copy2(src, dest)

    patterns = [
        # Package access needs to be first
        (r'\bprim_([a-zA-Z0-9_]+)::([a-zA-Z0-9_]+)', f'{prefix}prim_\\1::\\2'),
        # Enum type names
        (r'\bprim_([a-zA-Z0-9_]+)_e\b', f'{prefix}prim_\\1_e'),
        # Module/interface definitions
        (r'\bmodule\s+prim_([a-zA-Z0-9_]+)\b', f'module {prefix}prim_\\1'),
        (r'\binterface\s+prim_([a-zA-Z0-9_]+)\b', f'interface {prefix}prim_\\1'),
        # General primitive instantiations
        (r'\bprim_([a-zA-Z0-9_]+)\s+', f'{prefix}prim_\\1 '),
        # Include and import statements
        (r'`include\s+"prim_([^"]+)"', f'`include "{prefix}prim_\\1"'),
        (r'import\s+prim_([^;]+);', f'import {prefix}prim_\\1;'),
        # Package definitions
        (r'package\s+prim_([a-zA-Z0-9_]+)\s*;', f'package {prefix}prim_\\1;'),
    ]

    with fileinput.FileInput(dest, inplace=True) as file:
        for line in file:
            for pattern, replacement in patterns:
                line = re.sub(pattern, replacement, line)
            print(line, end='')


def export(export_dir: str, prefix: str):
    with tempfile.TemporaryDirectory() as temp_dir:
        logger.info(f"Created temporary directory: {temp_dir}")

        run_command(["git", "clone", "https://github.com/lowrisc/ibex.git"], cwd=temp_dir)
        ibex_dir = os.path.join(temp_dir, "ibex")

        venv_python = setup_venv(ibex_dir)

        run_command([venv_python, "-m", "fusesoc.main", "--cores-root", ".",
                    "run", "--target=lint", "--setup",
                    "--build-root", "./build/ibex_out",
                    "lowrisc:ibex:ibex_top"], cwd=ibex_dir)

        os.makedirs(export_dir, exist_ok=True)

        build_dir = os.path.join(ibex_dir, "build", "ibex_out", "src")
        files = find_files(build_dir)

        for file in files:
            process_file(file, export_dir, prefix)

        logger.info(f"Files exported to {export_dir}")


def get_args():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--prefix",
        "-p",
        default="ot_",
        help="Specify a uniquifying prefix to use on all primitive files"
    )
    parser.add_argument(
        "--export-dir",
        "-e",
        default="export",
        help="Specify an export directory"
    )
    parser.add_argument(
        "--clean",
        "-c",
        action="store_true",
        help="Force deletion of the export directory if it exists"
    )
    parser.add_argument(
        "--verbose",
        "-v",
        action="store_true",
        help="Use verbose logging"
    )
    return parser.parse_args()


def main():
    args = get_args()

    level = logging.INFO
    if args.verbose:
        level = logging.DEBUG
    logging.basicConfig(format="%(levelname)s: %(message)s", level=level)

    if os.path.exists(args.export_dir):
        if not args.clean:
            logger.error(f"export directory already exists; use --clean or pick another directory")
            exit(1)
        shutil.rmtree(args.export_dir)

    export(args.export_dir, args.prefix)


if __name__ == "__main__":
    main()
#ibex.core
CAPI=2:
name: lowrisc:export:ibex_top
description: Ibex CPU source code

filesets:
  rtl:
    files:
      - rtl/dv_fcov_macros.svh: {is_include_file: true}
      - rtl/ot_prim_assert_yosys_macros.svh: {is_include_file: true}
      - rtl/ot_prim_assert_standard_macros.svh: {is_include_file: true}
      - rtl/ot_prim_assert_dummy_macros.svh: {is_include_file: true}
      - rtl/ot_prim_assert_sec_cm.svh: {is_include_file: true}
      - rtl/ot_prim_util_get_scramble_params.svh: {is_include_file: true}
      - rtl/ot_prim_util_memload.svh: {is_include_file: true}
      - rtl/ot_prim_assert.sv
      - rtl/ot_prim_pkg.sv
      - rtl/ot_prim_util_pkg.sv
      - rtl/ot_prim_secded_pkg.sv
      - rtl/ibex_pkg.sv
      - rtl/ot_prim_cipher_pkg.sv
      - rtl/ot_prim_mubi_pkg.sv
      - rtl/ot_prim_count_pkg.sv
      - rtl/ot_prim_ram_1p_pkg.sv
      - rtl/ot_prim_and2.sv
      - rtl/ot_prim_badbit_ram_1p.sv
      - rtl/ot_prim_buf.sv
      - rtl/ot_prim_clock_gating.sv
      - rtl/ot_prim_clock_mux2.sv
      - rtl/ot_prim_count.sv
      - rtl/ot_prim_flop.sv
      - rtl/ot_prim_flop_macros.sv
      - rtl/ot_prim_generic_and2.sv
      - rtl/ot_prim_generic_buf.sv
      - rtl/ot_prim_generic_clock_gating.sv
      - rtl/ot_prim_generic_clock_mux2.sv
      - rtl/ot_prim_generic_flop.sv
      - rtl/ot_prim_generic_ram_1p.sv
      - rtl/ot_prim_lfsr.sv
      - rtl/ot_prim_mubi12_dec.sv
      - rtl/ot_prim_mubi12_sender.sv
      - rtl/ot_prim_mubi12_sync.sv
      - rtl/ot_prim_mubi16_dec.sv
      - rtl/ot_prim_mubi16_sender.sv
      - rtl/ot_prim_mubi16_sync.sv
      - rtl/ot_prim_mubi20_dec.sv
      - rtl/ot_prim_mubi20_sender.sv
      - rtl/ot_prim_mubi20_sync.sv
      - rtl/ot_prim_mubi24_dec.sv
      - rtl/ot_prim_mubi24_sender.sv
      - rtl/ot_prim_mubi24_sync.sv
      - rtl/ot_prim_mubi28_dec.sv
      - rtl/ot_prim_mubi28_sender.sv
      - rtl/ot_prim_mubi28_sync.sv
      - rtl/ot_prim_mubi32_dec.sv
      - rtl/ot_prim_mubi32_sender.sv
      - rtl/ot_prim_mubi32_sync.sv
      - rtl/ot_prim_mubi4_dec.sv
      - rtl/ot_prim_mubi4_sender.sv
      - rtl/ot_prim_mubi4_sync.sv
      - rtl/ot_prim_mubi8_dec.sv
      - rtl/ot_prim_mubi8_sender.sv
      - rtl/ot_prim_mubi8_sync.sv
      - rtl/ot_prim_onehot_check.sv
      - rtl/ot_prim_onehot_enc.sv
      - rtl/ot_prim_onehot_mux.sv
      - rtl/ot_prim_present.sv
      - rtl/ot_prim_prince.sv
      - rtl/ot_prim_ram_1p.sv
      - rtl/ot_prim_ram_1p_adv.sv
      - rtl/ot_prim_ram_1p_scr.sv
      - rtl/ot_prim_secded_22_16_dec.sv
      - rtl/ot_prim_secded_22_16_enc.sv
      - rtl/ot_prim_secded_28_22_dec.sv
      - rtl/ot_prim_secded_28_22_enc.sv
      - rtl/ot_prim_secded_39_32_dec.sv
      - rtl/ot_prim_secded_39_32_enc.sv
      - rtl/ot_prim_secded_64_57_dec.sv
      - rtl/ot_prim_secded_64_57_enc.sv
      - rtl/ot_prim_secded_72_64_dec.sv
      - rtl/ot_prim_secded_72_64_enc.sv
      - rtl/ot_prim_secded_hamming_22_16_dec.sv
      - rtl/ot_prim_secded_hamming_22_16_enc.sv
      - rtl/ot_prim_secded_hamming_39_32_dec.sv
      - rtl/ot_prim_secded_hamming_39_32_enc.sv
      - rtl/ot_prim_secded_hamming_72_64_dec.sv
      - rtl/ot_prim_secded_hamming_72_64_enc.sv
      - rtl/ot_prim_secded_hamming_76_68_dec.sv
      - rtl/ot_prim_secded_hamming_76_68_enc.sv
      - rtl/ot_prim_secded_inv_22_16_dec.sv
      - rtl/ot_prim_secded_inv_22_16_enc.sv
      - rtl/ot_prim_secded_inv_28_22_dec.sv
      - rtl/ot_prim_secded_inv_28_22_enc.sv
      - rtl/ot_prim_secded_inv_39_32_dec.sv
      - rtl/ot_prim_secded_inv_39_32_enc.sv
      - rtl/ot_prim_secded_inv_64_57_dec.sv
      - rtl/ot_prim_secded_inv_64_57_enc.sv
      - rtl/ot_prim_secded_inv_72_64_dec.sv
      - rtl/ot_prim_secded_inv_72_64_enc.sv
      - rtl/ot_prim_secded_inv_hamming_22_16_dec.sv
      - rtl/ot_prim_secded_inv_hamming_22_16_enc.sv
      - rtl/ot_prim_secded_inv_hamming_39_32_dec.sv
      - rtl/ot_prim_secded_inv_hamming_39_32_enc.sv
      - rtl/ot_prim_secded_inv_hamming_72_64_dec.sv
      - rtl/ot_prim_secded_inv_hamming_72_64_enc.sv
      - rtl/ot_prim_secded_inv_hamming_76_68_dec.sv
      - rtl/ot_prim_secded_inv_hamming_76_68_enc.sv
      - rtl/ot_prim_subst_perm.sv
      - rtl/ot_prim_xilinx_and2.sv
      - rtl/ot_prim_xilinx_buf.sv
      - rtl/ot_prim_xilinx_clock_gating.sv
      - rtl/ot_prim_xilinx_clock_mux2.sv
      - rtl/ot_prim_xilinx_flop.sv
      - rtl/ibex_pmp.sv
      - rtl/ibex_load_store_unit.sv
      - rtl/ibex_ex_block.sv
      - rtl/ibex_core.sv
      - rtl/ibex_multdiv_slow.sv
      - rtl/ibex_id_stage.sv
      - rtl/ibex_wb_stage.sv
      - rtl/ibex_prefetch_buffer.sv
      - rtl/ibex_counter.sv
      - rtl/ibex_controller.sv
      - rtl/ibex_branch_predict.sv
      - rtl/ibex_compressed_decoder.sv
      - rtl/ibex_fetch_fifo.sv
      - rtl/ibex_csr.sv
      - rtl/ibex_cs_registers.sv
      - rtl/ibex_dummy_instr.sv
      - rtl/ibex_alu.sv
      - rtl/ibex_if_stage.sv
      - rtl/ibex_decoder.sv
      - rtl/ibex_multdiv_fast.sv
      - rtl/ibex_lockstep.sv
      - rtl/ibex_register_file_latch.sv
      - rtl/ibex_register_file_fpga.sv
      - rtl/ibex_top.sv
      - rtl/ibex_register_file_ff.sv
      - rtl/ibex_icache.sv
    file_type: systemVerilogSource

  verilator_waivers:
    files:
      - rtl/ot_prim_generic_clock_gating.vlt
      - rtl/common.vlt
      - rtl/ot_prim_onehot_check.vlt
      - rtl/ot_prim_cipher.vlt
      - rtl/ot_prim_generic_clock_mux2.vlt
      - rtl/ot_prim_assert.vlt
      - rtl/verilator_waiver.vlt
      - rtl/ot_prim_xilinx_clock_gating.vlt
      - rtl/verilator_waiver.vlt
      - rtl/ot_prim_xilinx_clock_mux2.vlt
      - rtl/ot_prim_count.vlt
      - rtl/ot_prim_ram_1p_scr.vlt
      - rtl/ot_prim_generic_ram_1p.vlt
    file_type: vlt

targets:
  default:
    filesets:
      - rtl
      - tool_verilator ? (verilator_waivers)
    toplevel: ibex_top

ghost avatar Jan 03 '25 18:01 ghost