split mux-generation into separate function, use it for both out and outen
[pinmux.git] / src / bsv / actual_pinmux.py
1 import math
2 from string import digits
3 try:
4 from string import maketrans
5 except ImportError:
6 maketrans = str.maketrans
7
8
9 # ============== common bsv templates ============ #
10 # first argument is the io-cell number being assigned.
11 # second argument is the mux value.
12 # Third argument is the signal from the pinmap file
13 mux_wire = '''
14 rule assign_{2}_on_cell{0}(wrcell{0}_mux=={1});
15 {2}<=cell{0}_mux_in;
16 endrule
17 '''
18 dedicated_wire = '''
19 rule assign_{1}_on_cell{0};
20 {1}<=cell{0}_mux_in;
21 endrule
22 '''
23 # ============================================================
24 digits = maketrans('0123456789', ' ' * 10) # delete space later
25
26
27 def get_cell_bit_width(p):
28 max_num_cells = 0
29 for cell in p.muxed_cells:
30 max_num_cells = max(len(cell) - 1, max_num_cells)
31 return int(math.log(max_num_cells + 1, 2))
32
33
34 def cn(idx): # idx is an integer
35 return "cell%s_mux" % str(idx)
36
37
38 def transfn(temp):
39 """ removes the number from the string of signal name.
40 """
41 temp = temp.split('_')
42 if len(temp) == 2:
43 temp[0] = temp[0].translate(digits)
44 temp[0] = temp[0] .replace(' ', '')
45 return '_'.join(temp)
46
47
48 # XXX this needs to move into interface_decl.py
49 # and made to use ifaceoutfmtfn and ifaceinfmtfn
50 def fmt(ifaces, cell, idx, suffix=None):
51 """ blank entries need to output a 0 to the pin (it could just as
52 well be a 1 but we choose 0). reason: blank entries in
53 the pinmap.txt file indicate that there's nothing to choose
54 from. however the user may still set the muxer to that value,
55 and rather than throw an exception we choose to output... zero.
56 """
57 idx += 1
58 if idx < len(cell):
59 cell = cell[idx]
60 else:
61 cell = ''
62 if not cell:
63 return '0'
64 temp = transfn(cell)
65 x = ifaces.getifacetype(temp)
66 if x == 'input':
67 return '0' # inputs don't get passed through to the out mux
68 if suffix == '_outen' and x == 'out':
69 return '1'
70 return "wr%s%s" % (cell, suffix or '')
71
72 # XXX this needs to move into interface_decl.py
73 def mkcomment(ifaces, cell, idx, outenmode=False):
74 """ returns a comment string for the cell when muxed
75 """
76 idx += 1
77 if idx >= len(cell):
78 return ' // unused'
79 cname = cell[idx]
80 if not cname:
81 return ' // unused'
82 temp = transfn(cname)
83 x = ifaces.getifacetype(temp)
84 print (cname, x)
85 if x == 'input':
86 return ' // %s is an input' % cname
87 if outenmode and x == 'inout':
88 return ' // bi-directional'
89 if outenmode and x == 'out':
90 return ' // %s is an output' % cname
91
92 return ""
93
94
95 def mkmux(p, ifaces, cell, suffix, outenmode):
96 comment = 'outen' if outenmode else 'output'
97 fmtstr = "\t\t\twr%s==%d?%s:%s\n" # mux-selector format
98 ret = ''
99 ret += " // %s muxer for cell idx %s\n" % (comment, cell[0])
100 ret += " %s%s=\n" % (cn(cell[0]), suffix)
101 for i in range(
102 0, (1 << p.cell_bitwidth) - 1): # full mux range (minus 1)
103 comment = mkcomment(ifaces, cell, i, outenmode)
104 cf = fmt(ifaces, cell, i, suffix)
105 ret += fmtstr % (cn(cell[0]), i, cf, comment)
106 comment = mkcomment(ifaces, cell, i + 1, outenmode)
107 ret += "\t\t\t" + fmt(ifaces, cell, i + 1, suffix) # last line
108 ret += ";%s\n" % comment
109
110 return ret
111
112 def init(p, ifaces):
113 """ generates the actual output pinmux for each io-cell. blank lines
114 need to output "0" to the iopad, if there is no entry in
115 that column.
116
117 text is outputted in the format:
118 x_out =
119 muxer_sel==0 ? a :
120 muxer_sel==1 ? b :
121 muxer_sel==2 ? 0 :
122 d
123
124 last line doesn't need selector-logic, obviously.
125
126 note that it's *important* that all muxer options be covered
127 (hence going up to 1<<cell_bitwidth) even if the muxer cells
128 are blank (no entries), because muxer selection could be to
129 the last one, and we do not want the "default" (last line)
130 to be the output.
131 """
132 p.cell_bitwidth = get_cell_bit_width(p)
133 p.pinmux = ' '
134 global dedicated_wire
135 for cell in p.muxed_cells:
136
137 # first do the outputs
138 p.pinmux += mkmux(p, ifaces, cell, '_out', False)
139 p.pinmux += "\n"
140
141 # now do the output enablers (outens)
142 p.pinmux += mkmux(p, ifaces, cell, '_outen', True)
143
144 # ======================================================== #
145
146 # check each cell if "peripheral input/inout" then assign its wire
147 # Here we check the direction of each signal in the dictionary.
148 # We choose to keep the dictionary within the code and not user-input
149 # since the interfaces are always standard and cannot change from
150 # user-to-user. Plus this also reduces human-error as well :)
151 for i in range(0, len(cell) - 1):
152 cname = cell[i + 1]
153 if not cname: # skip blank entries, no need to test
154 continue
155 temp = transfn(cname)
156 x = ifaces.getifacetype(temp)
157 #print (cname, temp, x)
158 assert x is not None, "ERROR: The signal : " + \
159 str(cname) + \
160 " of pinmap.txt isn't present \nin the current" + \
161 " dictionary. Update dictionary or fix-typo."
162 if x == "input":
163 p.pinmux += \
164 mux_wire.format(cell[0], i, "wr" + cname) + "\n"
165 elif x == "inout":
166 p.pinmux += \
167 mux_wire.format(cell[0], i, "wr" + cname +
168 "_in") + "\n"
169 # ============================================================ #
170
171 # ================== Logic for dedicated pins ========= #
172 for cell in p.dedicated_cells:
173 p.pinmux += " %s_out=%s_io;\n" % (cn(cell[0]), cell[1])
174 temp = cell[1].translate(digits)
175 x = ifaces.getifacetype(temp)
176 if x == "input":
177 pinmux = pinmux + \
178 dedicated_wire.format(cell[0], "wr" + cell[1]) + "\n"
179 elif x == "inout":
180 pinmux = pinmux + \
181 dedicated_wire.format(cell[0], "wr" + cell[1] + "_in") + "\n"
182 # =======================================================#