aboutsummaryrefslogtreecommitdiff
path: root/sem6/dig/generate_test_file.py
blob: 2b8e37a79f1826355f9128a64db7cfdeb5c4a9d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python
"""
WOW THIS IS TERRIBLE
====
Documentation of the file definition thing
====
Its just a json string with the following values
    inputs: List of inputs, vectors are defined with "name,a,b" which becomes "std_logic_vector(a downto b)". Do not include the clock inhere if the "clk" param is used.
    outputs: Same as inputs but outputs. These are not checked, but they are added as signals to the output wave thing.
    testin: Test statements. Must be a 2D list or something like that, with [testindex][input_in_order]. ["0000", "0000"] is valid if there is 4 inputs, vectors are given as strings: [["0000", "1"]].
    testcount: Run number of times without any testinput. Handy if there are no inputs but a clock.
    clk: Define a new input to use as clock. The clock will be pulsed for every "testin", thus making the test twice as long.
    teststep: How long to wait with between each pulse. When using clk, it is the time between each pulse.
"""

import json
import argparse
import re
import sys
import os
import jinja2 as j2

test_define_re = re.compile("TEST_START(.*)TEST_STOP")

parser = argparse.ArgumentParser()
parser.add_argument("file", help="vhdl file to read from")
parser.add_argument("output", help="vhdl file to save to")

args = parser.parse_args()

def load_file_def(fname):
    filecontent = ""
    with open(fname, "r") as f:
        filecontent = f.read()

    groups = test_define_re.search(filecontent).groups()
    if groups:
        return json.loads(groups[0])
    else:
        print("No def in file", f=sys.stderr)

test_def = load_file_def(args.file)
name = os.path.splitext(args.file)[0]

def generate_vhdl_file(f, td, name):
    def tof(s):
        f.write(s)

    tof(f"""
library IEEE;
use IEEE.STD_LOGIC_1164.all;

entity test_{name} is
end test_{name};

architecture behavior of test_{name} is
    component {name} is
        port (
    """)

    # Generate PORT section
    first = True
    if "clk" in td:
        tof(f"{td['clk']}: IN STD_LOGIC")
        first = False
    for i in td["inputs"]:
        if not first:
            tof(";\n")
        first = False
        args = i.split(",")
        if len(args) > 1:
            tof(f"{args[0]} : IN STD_LOGIC_VECTOR({args[1]} downto {args[2]})")
        else:
            # Not a vector
            tof(f"{args[0]} : IN STD_LOGIC")
    for o in td["outputs"]:
        if not first:
            tof(";\n")
        first = False
        args = o.split(",")
        if len(args) > 1:
            tof(f"{args[0]} : OUT STD_LOGIC_VECTOR({args[1]} downto {args[2]})")
        else:
            # Not a vector
            tof(f"{args[0]} : OUT STD_LOGIC")
    tof(");\nend component;\n");

    # Define signals
    if "clk" in td:
        tof(f"signal in_{td['clk']}: STD_LOGIC;\n")
    for i in td["inputs"]:
        args = i.split(",")
        if len(args) > 1:
            tof(f"signal in_{args[0]} : STD_LOGIC_VECTOR({args[1]} downto {args[2]});\n")
        else:
            # Not a vector
            tof(f"signal in_{args[0]} : STD_LOGIC;\n")
    for i in td["outputs"]:
        args = i.split(",")
        if len(args) > 1:
            tof(f"signal out_{args[0]} : STD_LOGIC_VECTOR({args[1]} downto {args[2]});\n")
        else:
            # Not a vector
            tof(f"signal out_{args[0]} : STD_LOGIC;\n")
    tof(f"""\nbegin
        uut: {name} port map(\n""")

    first = True
    if "clk" in td:
        tof(f"{td['clk']} => in_{td['clk']}")
        first = False
    for i in td["inputs"]:
        if not first:
            tof(",\n")
        first = False
        args = i.split(",")
        tof(f"{args[0]} => in_{args[0]}")
    for i in td["outputs"]:
        if not first:
            tof(",\n")
        first = False
        args = i.split(",")
        tof(f"{args[0]} => out_{args[0]}")
    tof(");\n\nstim_proc: process\nbegin\n")

    def wait():
        tof(f"wait for {td.get('teststep', 1)} fs;")

    if "testin" in td:
        enum = enumerate(td["testin"])
    else:
        enum = enumerate([1] * td["testcount"])

    for tindex, t in enum:
        # Add clock
        if "clk" in td:
            tof(f"in_{td['clk']} <= '0';")
        for index, i in enumerate(td["inputs"]):
            args = i.split(",")
            if len(args) > 1:
                tof(f"in_{args[0]} <= \"{t[index]}\";")
            else:
                tof(f"in_{args[0]} <= '{t[index]}';")
        if "clk" in td:
            wait()
            tof(f"in_{td['clk']} <= '1';")
        wait()
    tof("wait;\nend process;\nend;")


with open(args.output, "w") as f:
    generate_vhdl_file(f, test_def, name)