| 1 |
8 |
gdevic |
#!/usr/bin/env python3
|
| 2 |
|
|
#
|
| 3 |
|
|
# This script reads 'exec_matrix.vh' file and compiles it into an alternate format
|
| 4 |
|
|
# that can be used with Xilinx toolchain.
|
| 5 |
|
|
#
|
| 6 |
|
|
# Xilinx synthesis tool is effectively not capable of processing that file.
|
| 7 |
|
|
# Altera Quartus has no problems compiling it.
|
| 8 |
|
|
#
|
| 9 |
|
|
#-------------------------------------------------------------------------------
|
| 10 |
|
|
# Copyright (C) 2016 Goran Devic
|
| 11 |
|
|
#
|
| 12 |
|
|
# This program is free software; you can redistribute it and/or modify it
|
| 13 |
|
|
# under the terms of the GNU General Public License as published by the Free
|
| 14 |
|
|
# Software Foundation; either version 2 of the License, or (at your option)
|
| 15 |
|
|
# any later version.
|
| 16 |
|
|
#
|
| 17 |
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
| 18 |
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
| 19 |
|
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
| 20 |
|
|
# more details.
|
| 21 |
|
|
#-------------------------------------------------------------------------------
|
| 22 |
|
|
import os
|
| 23 |
|
|
import io
|
| 24 |
|
|
import copy
|
| 25 |
|
|
import tokenize
|
| 26 |
|
|
from io import BytesIO
|
| 27 |
|
|
from tokenize import NAME, INDENT, DEDENT, ENCODING
|
| 28 |
|
|
|
| 29 |
|
|
# Input file to process
|
| 30 |
|
|
fname = "exec_matrix.vh"
|
| 31 |
|
|
|
| 32 |
|
|
# Output file to contain compiled version of the input
|
| 33 |
|
|
oname = "exec_matrix_compiled.vh"
|
| 34 |
|
|
|
| 35 |
|
|
# Output file to contain a list of temporary wires used by the compiled Verilog file
|
| 36 |
|
|
tname = "temp_wires.vh"
|
| 37 |
|
|
|
| 38 |
|
|
# Define a list of control signals that are 2-bits wide
|
| 39 |
|
|
ctls_wide = ['ctl_reg_gp_sel', 'ctl_reg_gp_hilo', 'ctl_reg_sys_hilo', 'ctl_pf_sel']
|
| 40 |
|
|
|
| 41 |
|
|
# Help recognizing control signal names
|
| 42 |
|
|
def is_ctl(name):
|
| 43 |
|
|
return name.startswith('ctl_') or name=='validPLA' or name=='nextM' or name=='setM1' \
|
| 44 |
|
|
or name=='fFetch' or name=='fMRead' or name=='fMWrite' or name=='fIORead' or name=='fIOWrite' \
|
| 45 |
13 |
gdevic |
or name=='ixy_d' or name=='setIXIY' or name=='nonRep' or name=='pc_inc_hold'
|
| 46 |
8 |
gdevic |
|
| 47 |
|
|
def str2tok(s):
|
| 48 |
|
|
t = io.BytesIO(bytes(s.encode()))
|
| 49 |
|
|
return list(tokenize.tokenize(t.readline))[1:-1]
|
| 50 |
|
|
|
| 51 |
|
|
def tok2str(tokens):
|
| 52 |
|
|
line = [ tokens[n][m].string for n in range(len(tokens)) for m in range(len(tokens[n])) ]
|
| 53 |
|
|
return ''.join(line)
|
| 54 |
|
|
|
| 55 |
|
|
def get_rval(tokens, i):
|
| 56 |
|
|
assert (tokens[i+1].string=='=' or tokens[i+1].string=='|=')
|
| 57 |
|
|
paren = list(str2tok('()'))
|
| 58 |
|
|
rval = paren[:1]
|
| 59 |
|
|
while (tokens[i+2].string!=';'):
|
| 60 |
|
|
rval.append(tokens[i+2])
|
| 61 |
|
|
i += 1
|
| 62 |
|
|
rval.extend(paren[1:2])
|
| 63 |
|
|
return [rval]
|
| 64 |
|
|
|
| 65 |
|
|
def decomment(s):
|
| 66 |
|
|
i = s.find('//') # Remove trailing comments from a line
|
| 67 |
|
|
if i>=0:
|
| 68 |
|
|
return s[:i]
|
| 69 |
|
|
i = s.find('/*') # Remove comments within a line
|
| 70 |
|
|
j = s.find('*/')
|
| 71 |
|
|
if i>=0 and j>=0:
|
| 72 |
|
|
return decomment(s[:i] + s[j+2:])
|
| 73 |
|
|
return s
|
| 74 |
|
|
|
| 75 |
|
|
#--------------------------------------------------------------------------------
|
| 76 |
|
|
# Generate a sequential-or form for all control wires
|
| 77 |
|
|
#--------------------------------------------------------------------------------
|
| 78 |
|
|
def sequential_or(f, t, tokens):
|
| 79 |
|
|
incond = False # Inside an "if" condition state
|
| 80 |
|
|
cond = [] # Condition nested lists
|
| 81 |
|
|
ccond = [] # Currently scanned condition list
|
| 82 |
|
|
ctls = {} # Dictionary of control wires and their equations
|
| 83 |
|
|
ccwires = [] # List of wires at the current condition list level
|
| 84 |
|
|
i = 0 # Current index into the tokens list
|
| 85 |
|
|
while i < len(tokens):
|
| 86 |
|
|
tok = tokens[i]
|
| 87 |
|
|
(toknum, tokval, _, _, _) = tok
|
| 88 |
|
|
if incond and not (toknum==NAME and tokval=='begin'):
|
| 89 |
|
|
if toknum != DEDENT and toknum != INDENT:
|
| 90 |
|
|
ccond.append(tok)
|
| 91 |
|
|
if toknum==NAME:
|
| 92 |
|
|
if tokval=='if':
|
| 93 |
|
|
incond = True
|
| 94 |
|
|
if tokval=='begin': # Push a condition list
|
| 95 |
|
|
incond = False
|
| 96 |
|
|
cond.append(copy.deepcopy(ccond))
|
| 97 |
|
|
ccond.clear()
|
| 98 |
|
|
ccwires.clear()
|
| 99 |
|
|
if tokval=='end': # Pop a condition list
|
| 100 |
|
|
cond.pop()
|
| 101 |
|
|
if is_ctl(tokval) and not incond:
|
| 102 |
|
|
rval = get_rval(tokens, i)
|
| 103 |
|
|
linesub = tok2str(cond)
|
| 104 |
|
|
rhs = tok2str(rval)
|
| 105 |
|
|
line = "{0} = {0} | ".format(tokval)
|
| 106 |
|
|
if tokval in ccwires: # Check for duplicate assignments
|
| 107 |
|
|
hint = [ cond[n][m].string for n in range(len(cond)) for m in range(len(cond[n])) ]
|
| 108 |
|
|
print ("WARNING: {0}: Multiple assignment of {1}".format(''.join(hint), tokval))
|
| 109 |
|
|
ccwires.append(tokval) # Track this wire as assigned at this condition level
|
| 110 |
|
|
if tokval in ctls_wide:
|
| 111 |
|
|
tr = linesub.translate(str.maketrans(dict.fromkeys('~','n'))) # Make temporary name
|
| 112 |
|
|
tmpname = "{0}_{1}_{2}".format(tokval, tr.translate(str.maketrans(dict.fromkeys('[]()&',None))), len(ccwires))
|
| 113 |
|
|
t.write("reg {0};\n".format(tmpname))
|
| 114 |
|
|
line = "{0} = {1};\n".format(tmpname, linesub) + line
|
| 115 |
|
|
line += "({{{0},{0}}}){1}".format(tmpname, rhs)
|
| 116 |
|
|
else:
|
| 117 |
|
|
line += linesub + rhs
|
| 118 |
|
|
line = line.replace(')(', ')&(')
|
| 119 |
|
|
line = line.replace('&&', '&')
|
| 120 |
|
|
line = line.replace('(1)&', '')
|
| 121 |
|
|
line = line.replace('&(1)', '')
|
| 122 |
|
|
i += len(rval[0])
|
| 123 |
|
|
f.write ('{0};\n'.format(line))
|
| 124 |
|
|
i += 1
|
| 125 |
|
|
|
| 126 |
|
|
#--------------------------------------------------------------------------------
|
| 127 |
|
|
tokens = []
|
| 128 |
|
|
# Input file which we are processing
|
| 129 |
|
|
with open(fname) as f:
|
| 130 |
|
|
lines = f.readlines()
|
| 131 |
|
|
|
| 132 |
|
|
for line in lines:
|
| 133 |
|
|
src = decomment(line)
|
| 134 |
|
|
src = bytes(src.encode())
|
| 135 |
|
|
src = io.BytesIO(src)
|
| 136 |
|
|
toklist = list(tokenize.tokenize(src.readline))
|
| 137 |
|
|
tokens.extend(toklist)
|
| 138 |
|
|
|
| 139 |
|
|
with open(oname, 'w') as f:
|
| 140 |
|
|
with open(tname, 'w') as t:
|
| 141 |
|
|
f.write("// Automatically generated by gencompile.py\n\n")
|
| 142 |
|
|
t.write("// Automatically generated by gencompile.py\n\n")
|
| 143 |
|
|
sequential_or(f, t, tokens)
|
| 144 |
|
|
|
| 145 |
|
|
# Touch a file that includes 'exec_matrix_compiled.vh' to ensure it will recompile correctly
|
| 146 |
|
|
os.utime("execute.v", None)
|