OpenCores
URL https://opencores.org/ocsvn/a-z80/a-z80/trunk

Subversion Repositories a-z80

[/] [a-z80/] [trunk/] [cpu/] [control/] [genmatrix.py] - Blame information for rev 4

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 gdevic
#!/usr/bin/env python
2
#
3
# This script reads A-Z80 instruction timing data from a spreadsheet text file
4
# and generates a Verilog include file defining the control block execution matrix.
5
# Macros in the timing spreadsheet are substituted using a list of keys stored
6
# in the macros file. See the macro file for the format information.
7
#
8
# Input timing file is exported from the Excel file as a TAB-delimited text file.
9
#
10
#-------------------------------------------------------------------------------
11
#  Copyright (C) 2014  Goran Devic
12
#
13
#  This program is free software; you can redistribute it and/or modify it
14
#  under the terms of the GNU General Public License as published by the Free
15
#  Software Foundation; either version 2 of the License, or (at your option)
16
#  any later version.
17
#
18
#  This program is distributed in the hope that it will be useful, but WITHOUT
19
#  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
#  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
21
#  more details.
22
#-------------------------------------------------------------------------------
23
import string
24
import sys
25
import csv
26
import os
27
 
28
# Input file exported from a timing spreadsheet:
29
fname = "Timings.csv"
30
 
31
# Input file containing macro substitution keys
32
kname = "timing_macros.i"
33
 
34
# Set this to 1 if you want abbreviated matrix (no-action lines removed)
35
abbr = 1
36
 
37
# Set this to 1 if you want debug $display() printout on each PLA line
38
debug = 0
39
 
40
# Print this string in front of every line that starts with "ctl_". This helps
41
# formatting the output to be more readable.
42
ctl_prefix = "\n"+" "*19
43
 
44
# Read in the content of the macro substitution file
45
macros = []
46
with open(kname, 'r') as f:
47
    for line in f:
48
        if len(line.strip())>0 and line[0]!='/':
49
            # Wrap up non-starting //-style comments into /* ... */ so the
50
            # line can be concatenated while preserving comments
51
            if line.find("//")>0:
52
                macros.append( line.rstrip().replace("//", "/*", 1) + " */" )
53
            else:
54
                macros.append(line.rstrip())
55
 
56
# List of errors / keys and macros that did not match. We stash them as we go
57
# and then print at the end so it is easier to find them
58
errors = []
59
 
60
# Returns a substitution string given the section name (key) and the macro token
61
# This is done by simply traversing macro substitution list of lines, finding a
62
# section that starts with a :key and copying the substitution lines verbatim.
63
def getSubst(key, token):
64
    subst = []
65
    multiline = False
66
    validset = False
67
    if key=="Comments":                 # Special case: ignore "Comments" column!
68
        return ""
69
    for l in macros:
70
        if multiline==True:
71
            # Multiline copies lines until a char at [0] is not a space
72
            if len(l.strip())==0 or l[0]!=' ':
73
                return '\n' + "\n".join(subst)
74
            else:
75
                subst.append(l)
76
        lx = l.split(' ')               # Split the string and then ignore (duplicate)
77
        lx = filter(None, lx)           # spaces in the list left by the split()
78
        if l.startswith(":"):           # Find and recognize a matching set (key) section
79
            if validset:                # Error if there is a new section going from the macthing one
80
                break                   # meaning we did not find our macro in there
81
            if l[1:]==key:
82
                validset = True
83
        elif validset and lx[0]==token:
84
            if len(lx)==1:
85
                return ""
86
            if lx[1]=='\\':             # Multi-line macro state starts with '\' character
87
                multiline = True
88
                continue
89
            lx.pop(0)
90
            s = " ".join(lx)
91
            return ' ' + s.strip()
92
    err = "{0} not in {1}".format(token, key)
93
    if err not in errors:
94
        errors.append(err)
95
    return " --- {0} ?? {1} --- ".format(token, key)
96
 
97
# Read the content of a file and using the csv reader and remove any quotes from the input fields
98
content = []                            # Content of the spreadsheet timing file
99
with open(fname, 'rb') as csvFile:
100
    reader = csv.reader(csvFile, delimiter='\t', quotechar='"')
101
    for row in reader:
102
        content.append('\t'.join(row))
103
 
104
# The first line is special: it contains names of sets for our macro substitutions
105
tkeys = {}                              # Spreadsheet table column keys
106
tokens = content.pop(0).split('\t')
107
for col in range(len(tokens)):
108
    if len(tokens[col])==0:
109
        continue
110
    tkeys[col] = tokens[col]
111
 
112
# Process each line separately (stateless processor)
113
imatrix = []    # Verilog execution matrix code
114
for line in content:
115
    col = line.split('\t')              # Split the string into a list of columns
116
    col_clean = filter(None, col)       # Removed all empty fields (between the separators)
117
    if len(col_clean)==0:               # Ignore completely empty lines
118
        continue
119
 
120
    if col_clean[0].startswith('//'):   # Print comment lines
121
        imatrix.append(col_clean[0])
122
 
123
    if col_clean[0].startswith("#end"): # Print the end of a condition
124
        imatrix.append("end\n")
125
 
126
    if col_clean[0].startswith('#if'):  # Print the start of a condition
127
        s = col_clean[0]
128
        tag = s.find(":")
129
        condition = s[4:tag]
130
        imatrix.append("if ({0}) begin".format(condition.strip()))
131
        if debug and len(s[tag:])>1:    # Print only in debug and there is something to print
132
            imatrix.append("    $display(\"{0}\");".format(s[4:]))
133
 
134
    # We recognize 2 kinds of timing statements based on the starting characters:
135
    # "#0"..        common timings using M and T cycles (M being optional)
136
    # "#always"     timing that does not depend on M and T cycles (ex. ALU operations)
137
    if col_clean[0].startswith('#0') or col_clean[0].startswith('#always'):
138
        # M and T states are hard-coded in the table at the index 1 and 2
139
        if col_clean[0].startswith('#0'):
140
            if col[1]=='?':     # M is optional, use '?' to skip it
141
                state = "    if (T{0}) begin ".format(col[2])
142
            else:
143
                state = "    if (M{0} && T{1}) begin ".format(col[1], col[2])
144
        else:
145
            state = "    begin "
146
 
147
        # Loop over all other columns and perform verbatim substitution
148
        action = ""
149
        for i in range(3,len(col)):
150
            # There may be multiple tokens separated by commas
151
            tokList = col[i].strip().split(',')
152
            tokList =  filter(None, tokList)   # Filter out empty lines
153
            for token in tokList:
154
                token = token.strip()
155
                if i in tkeys and len(token)>0:
156
                    macro = getSubst(tkeys[i], token)
157
                    if macro.strip().startswith("ctl_"):
158
                        action += ctl_prefix
159
                    action += macro
160
                    if state.find("ERROR")>=0:
161
                        print "{0} {1}".format(state, action)
162
                        break
163
 
164
        # Complete and write out a line
165
        if abbr and len(action)==0:
166
            continue
167
        imatrix.append("{0}{1} end".format(state, action))
168
 
169
# Create a file containing the logic matrix code
170
with open('exec_matrix.i', 'w') as file:
171
    file.write("// Automatically generated by genmatrix.py\n")
172
    # If there were errors, print them first (and output to the console)
173
    if len(errors)>0:
174
        for error in errors:
175
            print error
176
            file.write(error + "\n")
177
        file.write("-" * 80 + "\n")
178
    for item in imatrix:
179
        file.write("{}\n".format(item))
180
 
181
# Touch a file that includes 'exec_matrix.i' to ensure it will recompile correctly
182
os.utime("execute.sv", None)

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.