bff3163012a1837aaf7d4849f8cd29984d3488a1
[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
74
75 def mkcomment(ifaces, cell, idx, outenmode=False):
76 """ returns a comment string for the cell when muxed
77 """
78 idx += 1
79 if idx >= len(cell):
80 return ' // unused'
81 cname = cell[idx]
82 if not cname:
83 return ' // unused'
84 temp = transfn(cname)
85 x = ifaces.getifacetype(temp)
86 print (cname, x)
87 if x == 'input':
88 return ' // %s is an input' % cname
89 if outenmode and x == 'inout':
90 return ' // bi-directional'
91 if outenmode and x == 'out':
92 return ' // %s is an output' % cname
93
94 return ""
95
96
97 def mkmux(p, ifaces, cell, suffix, outenmode):
98 comment = 'outen' if outenmode else 'output'
99 fmtstr = "\t\t\twr%s==%d?%s:%s\n" # mux-selector format
100 ret = ''
101 ret += " // %s muxer for cell idx %s\n" % (comment, cell[0])
102 ret += " %s%s=\n" % (cn(cell[0]), suffix)
103 for i in range(
104 0, (1 << p.cell_bitwidth) - 1): # full mux range (minus 1)
105 comment = mkcomment(ifaces, cell, i, outenmode)
106 cf = fmt(ifaces, cell, i, suffix)
107 ret += fmtstr % (cn(cell[0]), i, cf, comment)
108 comment = mkcomment(ifaces, cell, i + 1, outenmode)
109 ret += "\t\t\t" + fmt(ifaces, cell, i + 1, suffix) # last line
110 ret += ";%s\n" % comment
111
112 return ret
113
114
115 def init(p, ifaces):
116 """ generates the actual output pinmux for each io-cell. blank lines
117 need to output "0" to the iopad, if there is no entry in
118 that column.
119
120 text is outputted in the format:
121 x_out =
122 muxer_sel==0 ? a :
123 muxer_sel==1 ? b :
124 muxer_sel==2 ? 0 :
125 d
126
127 last line doesn't need selector-logic, obviously.
128
129 note that it's *important* that all muxer options be covered
130 (hence going up to 1<<cell_bitwidth) even if the muxer cells
131 are blank (no entries), because muxer selection could be to
132 the last one, and we do not want the "default" (last line)
133 to be the output.
134 """
135 p.cell_bitwidth = get_cell_bit_width(p)
136 p.pinmux = ' '
137 global dedicated_wire
138 for cell in p.muxed_cells:
139
140 # first do the outputs
141 p.pinmux += mkmux(p, ifaces, cell, '_out', False)
142 p.pinmux += "\n"
143
144 # now do the output enablers (outens)
145 p.pinmux += mkmux(p, ifaces, cell, '_outen', True)
146
147 # ======================================================== #
148
149 # check each cell if "peripheral input/inout" then assign its wire
150 # Here we check the direction of each signal in the dictionary.
151 # We choose to keep the dictionary within the code and not user-input
152 # since the interfaces are always standard and cannot change from
153 # user-to-user. Plus this also reduces human-error as well :)
154 p.pinmux += "\n"
155 p.pinmux += " // priority-in-muxer for cell idx %s\n" % (cell[0])
156 for i in range(0, len(cell) - 1):
157 cname = cell[i + 1]
158 if not cname: # skip blank entries, no need to test
159 continue
160 temp = transfn(cname)
161 x = ifaces.getifacetype(temp)
162 #print (cname, temp, x)
163 assert x is not None, "ERROR: The signal : " + \
164 str(cname) + \
165 " of pinmap.txt isn't present \nin the current" + \
166 " dictionary. Update dictionary or fix-typo."
167 if x == "input":
168 p.pinmux += \
169 mux_wire.format(cell[0], i, "wr" + cname) + "\n"
170 elif x == "inout":
171 p.pinmux += \
172 mux_wire.format(cell[0], i, "wr" + cname +
173 "_in") + "\n"
174 # ============================================================ #
175
176 # ================== Logic for dedicated pins ========= #
177 for cell in p.dedicated_cells:
178 p.pinmux += " %s_out=%s_io;\n" % (cn(cell[0]), cell[1])
179 temp = cell[1].translate(digits)
180 x = ifaces.getifacetype(temp)
181 if x == "input":
182 pinmux = pinmux + \
183 dedicated_wire.format(cell[0], "wr" + cell[1]) + "\n"
184 elif x == "inout":
185 pinmux = pinmux + \
186 dedicated_wire.format(cell[0], "wr" + cell[1] + "_in") + "\n"
187 # =======================================================#