#!/usr/bin/env python3
"""
Generating testlists for following open-source test suites
    - riscv-tests
    - riscv-arch-tests
    - ePMP directed tests
"""

# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

import os
import argparse
import sys

def add_configs_and_handwritten_directed_tests():
    testlist_string = '''# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

##########################################################

# This file is generated by gen_testlist.py script and largely copies
# the formatting of the testlist.yaml used by riscv-dv, but only specifies
# directed tests.
#
# - All paths are relative to THIS FILE.
# - Each 'test' can specify a config by name to re-use common configuration
# - If a test redefines a key already in the config, the test option takes priority.

##########################################################

- config: riscv-tests
  ld_script: link.ld
  includes: .
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
  rtl_test: core_ibex_base_test
  rtl_params:
    PMPEnable: 1
  timeout_s: 300

- config: riscv-arch-tests
  ld_script: link.ld
  includes: .
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-arch-tests/riscv-test-suite/env/
            -I../../../vendor/riscv-isa-sim/arch_test_target/spike/
  rtl_test: core_ibex_base_test
  rtl_params:
    PMPEnable: 1
  timeout_s: 300

- config: epmp-tests
  ld_script: ../../../../vendor/riscv-isa-sim/tests/mseccfg/mseccfg_test.ld
  includes: .
  gcc_opts: -march=rv32imc -O2 -I . -I ./. -I ../softfloat -I ../riscv -fno-builtin-printf
            -fdata-sections -fno-section-anchors -DPRINTF_SUPPORTED=1
            ../../../vendor/riscv-isa-sim/tests/mseccfg/crt.S
            ../../../vendor/riscv-isa-sim/tests/mseccfg/syscalls.c
            -mcmodel=medany -static -nostdlib -nostartfiles -lm -lgcc
            -Wl,-M -Wl,-Map=link.log
  rtl_test: core_ibex_base_test
  rtl_params:
    PMPEnable: 1
  timeout_s: 300
'''
    # Populate any handwritten directed tests below
    # and with suitable config
    available_directed_tests = '''
# Custom directed tests

- test: empty
  desc: >
    Empty directed test
  iterations: 1
  test_srcs: empty/empty.S
  config: riscv-tests

- test: mcounteren_test
  desc: >
    Tests the mcounteren CSR: reset value, hardwired-zero bit 1 (time),
    and U-mode counter access gating.
  iterations: 1
  test_srcs: mcounteren_test/mcounteren_test.S
  config: riscv-tests

- test: mcounteren_lock_test
  desc: >
    Tests that mcounteren retains its value after mcounteren_writable_i is
    de-asserted mid-simulation (write-lock).
  iterations: 1
  rtl_test: core_ibex_mcounteren_lock_test
  test_srcs: mcounteren_test/mcounteren_lock_test.S
  config: riscv-tests

- test: pmp_mseccfg_test_rlb1_l0_0_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DRLB -DSET_PMP_L=0 -DSET_PMP_L_PREV=0

- test: pmp_mseccfg_test_rlb1_l0_1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DRLB -DSET_PMP_L=1 -DSET_PMP_L_PREV=0

- test: pmp_mseccfg_test_rlb1_l1_0_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DRLB -DSET_PMP_L=0 -DSET_PMP_L_PREV=1

- test: pmp_mseccfg_test_rlb1_l1_1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DRLB -DSET_PMP_L=1 -DSET_PMP_L_PREV=1

- test: pmp_mseccfg_test_rlb0_l0_0_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DSET_PMP_L=0 -DSET_PMP_L_PREV=0

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_r1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_R1

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_w1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_W1

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_x1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_X1

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_r1_w1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_R1_W1

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_r1_x1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_R1_X1

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_w1_x1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_W1_X1

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_r1_w1_x1_u0
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_R1_W1_X1

- test: pmp_mseccfg_test_rlb1_l0_0_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DRLB -DSET_PMP_L=0 -DSET_PMP_L_PREV=0 -DU_MODE

- test: pmp_mseccfg_test_rlb1_l0_1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DRLB -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DU_MODE

- test: pmp_mseccfg_test_rlb1_l1_0_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DRLB -DSET_PMP_L=0 -DSET_PMP_L_PREV=1 -DU_MODE

- test: pmp_mseccfg_test_rlb1_l1_1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DRLB -DSET_PMP_L=1 -DSET_PMP_L_PREV=1 -DU_MODE

- test: pmp_mseccfg_test_rlb0_l0_0_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DPMP_REGION=4 -DSET_PMP_L=0 -DSET_PMP_L_PREV=0 -DU_MODE

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1 -DU_MODE

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_r1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_R1 -DU_MODE

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_w1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_W1 -DU_MODE

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_x1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_X1 -DU_MODE

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_r1_w1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_R1_W1 -DU_MODE

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_r1_x1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_R1_X1 -DU_MODE

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_w1_x1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_W1_X1 -DU_MODE

- test: pmp_mseccfg_test_rlb0_l0_1_next_l1_r1_w1_x1_u1
  desc: >
    mseccfg test
  iterations: 1
  test_srcs: pmp_mseccfg_test/pmp_mseccfg_test.S
  config: riscv-tests
  gcc_opts: -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
            -I../../../vendor/riscv-test-env/
            -I../../../vendor/riscv-test-env/p/
            -I../../../vendor/riscv-tests/isa/macros/scalar/
            -DSET_PMP_L=1 -DSET_PMP_L_PREV=0 -DPMP_NEXT_L1_R1_W1_X1 -DU_MODE

- test: access_pmp_overlap
  desc: >
    PMP access basic test
  iterations: 1
  test_srcs: access_pmp_overlap/access_pmp_overlap.S
  config: riscv-tests

- test: u_mode_exec_test
  desc: >
    PMP U mode exec test
  iterations: 1
  test_srcs: u_mode_exec_test/u_mode_exec_test.S
  config: riscv-tests
'''
    testlist_string += available_directed_tests
    with open('directed_testlist.yaml', "a") as f:
        f.write(testlist_string)

def append_directed_testlist(tests, test_suite, test_suite_name, is_assembly):
    testlist_string = '''
# Test-suite: {test_suite_name}
'''.format(test_suite_name = test_suite_name)
    extension = '.S' if is_assembly else '.c'
    extension_grep = ' | egrep .S' if is_assembly else ' | egrep .c'

    for test_group_name in tests:
        available_tests = os.popen('ls '+test_suite+test_group_name+extension_grep).read()
        available_testlist = []
        for test in available_tests.split('\n')[:-1]:
            available_testlist.append(test)
        for test_name_str in available_testlist:
            test_name = test_name_str.split(extension)[0]
            testlist_string = testlist_string + '''
- test: {test_name}
  desc: >
    riscv test - {test_name}
  iterations: 1
  test_srcs: {test_suite}{test_group_name}/{test_name}{extension}
  config: {config}
'''.format(test_name = test_name, test_group_name = test_group_name, test_suite = test_suite,
    config = test_suite_name, extension = extension)

    with open('directed_testlist.yaml', "a") as f:
        f.write(testlist_string)

def list_tests(dir):
    testlist_str = os.popen('ls '+dir).read()
    testlist = []
    for test in testlist_str.split('\n')[:-1]:
        testlist.append(test)
        print(testlist)
    return testlist

def _main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument('--add_tests',
                        type=str, required=True,
                        help='''List test-suite name(s) from following:
                              1) riscv-tests
                              2) riscv-arch-tests
                              3) epmp-tests

                              e.g. --add_tests=riscv-tests,epmp_tests
                              ''')

    args = parser.parse_args()
    test_suite = args.add_tests
    test_suite_list = test_suite.split(',')

    # remove any previous yaml file
    with open('directed_testlist.yaml','r+') as file:
        file.truncate(0)

    # add headers and configs, also adding any handwritten directed tests
    add_configs_and_handwritten_directed_tests()

    if 'riscv-tests' in test_suite_list or test_suite == 'all':
        isa_tests = ['rv32mi', 'rv32uc', 'rv32um', 'rv32ui']
        append_directed_testlist(isa_tests, '../../../../vendor/riscv-tests/isa/', 'riscv-tests', 1)

    if 'riscv-arch-tests' in test_suite_list or test_suite == 'all':
        arch_tests = ['rv32i_m/M/src', 'rv32i_m/C/src', 'rv32i_m/Zifencei/src', 'rv32i_m/I/src', 'rv32i_m/B/src']
        append_directed_testlist(arch_tests, '../../../../vendor/riscv-arch-tests/riscv-test-suite/', 'riscv-arch-tests', 1)

    if 'epmp-tests' in test_suite_list or test_suite == 'all':
        append_directed_testlist({'outputs'}, '../../../../vendor/riscv-isa-sim/tests/mseccfg/gengen_src/', 'epmp-tests', 0)

    # Always return 0 (success), even if the test failed. We've successfully
    # generated a comparison log either way and we don't want to stop Make from
    # gathering them all up for us.
    return 0

if __name__ == '__main__':
    sys.exit(_main())
