when muxwidth == 1 output pin directly
[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 cn(idx): # idx is an integer
28 return "cell%s_mux" % str(idx)
29
30
31 def transfn(temp):
32 """ removes the number from the string of signal name.
33 """
34 temp = temp.split('_')
35 if len(temp) == 2:
36 temp[0] = temp[0].translate(digits)
37 temp[0] = temp[0] .replace(' ', '')
38 return '_'.join(temp)
39
40
41 # XXX this needs to move into interface_decl.py
42 # and made to use ifaceoutfmtfn and ifaceinfmtfn
43 def fmt(ifaces, cells, idx, suffix=None):
44 """ blank entries need to output a 0 to the pin (it could just as
45 well be a 1 but we choose 0). reason: blank entries in
46 the pinmap.txt file indicate that there's nothing to choose
47 from. however the user may still set the muxer to that value,
48 and rather than throw an exception we choose to output... zero.
49
50 NOTE: IMPORTANT. when a function is an output-only there
51 is a special-case assumption that:
52 * (a) GPIO is always the first mux entry
53 * (b) GPIO's outen is also used to set the pad
54 the reason for this is that it is assumed better that
55 multiple pads be switched simutaneously to outputs
56 by setting the GPIO direction rather than having them
57 set arbitrarily by changing the muxer registers.
58 """
59 idx += 1
60 if idx < len(cells):
61 cell = cells[idx]
62 else:
63 cell = ''
64 #print "fmt", idx, cells, cell
65 if not cell:
66 return 'val0'
67 temp = transfn(cell)
68 x = ifaces.getifacetype(temp)
69 if x == 'input':
70 return 'val0' # inputs don't get passed through to the out mux
71 if suffix == '_outen' and x == 'out':
72 return "wr%s%s" % (cells[1], suffix or '') # USE GPIO FOR SELECTION
73 if x == 'out': # sigh hack, should be using interface_decl
74 suffix = ''
75 return "wr%s%s" % (cell, suffix or '')
76
77 # XXX this needs to move into interface_decl.py
78
79
80 def mkcomment(ifaces, cell, idx, outenmode=False):
81 """ returns a comment string for the cell when muxed
82 """
83 idx += 1
84 if idx >= len(cell):
85 return ' // unused'
86 cname = cell[idx]
87 if not cname:
88 return ' // unused'
89 temp = transfn(cname)
90 x = ifaces.getifacetype(temp)
91 #print (cname, x)
92 if x == 'input':
93 return ' // %s is an input' % cname
94 if outenmode and x == 'inout':
95 return ' // bi-directional'
96 if outenmode and x == 'out':
97 return ' // %s is an output' % cname
98
99 return ""
100
101
102 def mkmux(p, ifaces, cell, suffix, outenmode):
103 """ creates a straight many-to-one muxer that accepts
104 multiple inputs and, based on an "address" routes
105 a given indexed input through to the (one) output
106 """
107 cellnum = cell[0]
108 comment = 'outen' if outenmode else 'output'
109 fmtstr = "\t\t\twr%s==%d?%s:%s\n" # mux-selector format
110 ret = ''
111 ret += " // %s muxer for cell idx %s\n" % (comment, cellnum)
112 ret += " %s%s=\n" % (cn(cellnum), suffix)
113 i = 0
114 mwid = p.get_muxwidth(cellnum)
115 if mwid > 1:
116 for i in range(0, mwid - 1): # full mux range (minus 1)
117 comment = mkcomment(ifaces, cell, i, outenmode)
118 cf = fmt(ifaces, cell, i, suffix)
119 ret += fmtstr % (cn(cell[0]), i, cf, comment)
120 i += 1
121 comment = mkcomment(ifaces, cell, i, outenmode)
122 ret += "\t\t\t" + fmt(ifaces, cell, i, suffix) # last line
123 ret += ";%s\n" % comment
124
125 return ret
126
127
128 def init(p, ifaces):
129 """ generates the actual output pinmux for each io-cell. blank lines
130 need to output "0" to the iopad, if there is no entry in
131 that column.
132
133 text is outputted in the format:
134 x_out =
135 muxer_sel==0 ? a :
136 muxer_sel==1 ? b :
137 muxer_sel==2 ? 0 :
138 d
139
140 last line doesn't need selector-logic, obviously.
141
142 note that it's *important* that all muxer options be covered
143 (hence going up to 1<<cell_bitwidth) even if the muxer cells
144 are blank (no entries), because muxer selection could be to
145 the last one, and we do not want the "default" (last line)
146 to be the output.
147 """
148 p.pinmux = ' '
149 global dedicated_wire
150 for cell in p.muxed_cells:
151
152 cellidx = cell[0]
153
154 p.pinmux += " // --------------------\n"
155 p.pinmux += " // ----- cell %s -----\n\n" % (cellidx)
156
157 # first do the outputs
158 p.pinmux += mkmux(p, ifaces, cell, '_out', False)
159 p.pinmux += "\n"
160
161 # now do the output enablers (outens)
162 p.pinmux += mkmux(p, ifaces, cell, '_outen', True)
163
164 # ======================================================== #
165
166 # check each cell if "peripheral input/inout" then assign its wire
167 # Here we check the direction of each signal in the dictionary.
168 # We choose to keep the dictionary within the code and not user-input
169 # since the interfaces are always standard and cannot change from
170 # user-to-user. Plus this also reduces human-error as well :)
171 p.pinmux += "\n"
172 p.pinmux += " // priority-in-muxer for cell idx %s\n" % (cellidx)
173 for i in range(0, len(cell) - 1):
174 cname = cell[i + 1]
175 if not cname: # skip blank entries, no need to test
176 continue
177 temp = transfn(cname)
178 x = ifaces.getifacetype(temp)
179 print (cname, temp, x)
180 assert x is not None, "ERROR: The signal : " + \
181 str(cname) + \
182 " of pinmap.txt isn't present \nin the current" + \
183 " dictionary. Update dictionary or fix-typo."
184 bwid = p.get_muxbitwidth(cellidx)
185 if bwid > 0:
186 muxcell(p, cname, x, cell, i)
187 else:
188 dedcell(p, x, cell)
189
190 # ================== Logic for dedicated pins ========= #
191 p.pinmux += "\n /*=========================================*/\n"
192 p.pinmux += " // dedicated cells\n\n"
193 for cell in p.dedicated_cells:
194 p.pinmux += " // dedicated cell idx %s\n" % (cell[0])
195 p.pinmux += " %s_out=%s_io;\n" % (cn(cell[0]), cell[1])
196 temp = transfn(cell[1])
197 x = ifaces.getifacetype(temp)
198 #print cell, temp, x
199 dedcell(p, x, cell)
200
201 def muxcell(p, cname, x, cell, i):
202 if x == "input":
203 p.pinmux += \
204 mux_wire.format(cell[0], i, "wr" + cname) + "\n"
205 elif x == "inout":
206 p.pinmux += \
207 mux_wire.format(cell[0], i, "wr" + cname +
208 "_in") + "\n"
209 def dedcell(p, x, cell):
210 if x == "input":
211 p.pinmux += \
212 dedicated_wire.format(cell[0], "wr" + cell[1]) + "\n"
213 elif x == "inout":
214 p.pinmux += \
215 dedicated_wire.format(cell[0], "wr" + cell[1] + "_in") + "\n"