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