]> sigrok.org Git - libsigrokdecode.git/blame - decoders/mdio/pd.py
pwm: Use self.{ss,es}_block for consistency across PDs.
[libsigrokdecode.git] / decoders / mdio / pd.py
CommitLineData
e4302cbe
AJ
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
5##
6## This program is free software; you can redistribute it and/or modify
7## it under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 2 of the License, or
9## (at your option) any later version.
10##
11## This program is distributed in the hope that it will be useful,
12## but WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14## GNU General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
17## along with this program; if not, write to the Free Software
18## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19##
20
21import sigrokdecode as srd
22
23class Decoder(srd.Decoder):
24 api_version = 2
25 id = 'mdio'
26 name = 'MDIO'
27 longname = 'Management Data Input/Output'
28 desc = 'Half-duplex sync serial bus for MII management between MAC and PHY.'
29 license = 'gplv2+'
30 inputs = ['logic']
31 outputs = ['mdio']
32 channels = (
33 {'id': 'mdc', 'name': 'MDC', 'desc': 'Clock'},
34 {'id': 'mdio', 'name': 'MDIO', 'desc': 'Data'},
35 )
36 annotations = (
37 ('mdio-data', 'MDIO data'),
38 ('mdio-bits', 'MDIO bits'),
39 ('errors', 'Human-readable errors'),
40 )
41 annotation_rows = (
42 ('mdio-data', 'MDIO data', (0,)),
43 ('mdio-bits', 'MDIO bits', (1,)),
44 ('other', 'Other', (2,)),
45 )
46
47 def __init__(self):
48 self.oldmdc = 0
49 self.ss_block = -1
50 self.samplenum = -1
51 self.oldpins = None
52 self.reset_decoder_state()
53
54 def start(self):
55 self.out_python = self.register(srd.OUTPUT_PYTHON)
56 self.out_ann = self.register(srd.OUTPUT_ANN)
57
58 def putw(self, data):
59 self.put(self.ss_block, self.samplenum, self.out_ann, data)
60
61 def putbit(self, mdio, start, stop):
62 # Bit annotations.
63 self.put(start, stop, self.out_ann, [1, ['%d' % mdio]])
64
65 def putdata(self):
66 # FIXME: Only pass data, no bits.
67 # Pass MDIO bits and then data to the next PD up the stack.
68 ss, es = self.mdiobits[-1][1], self.mdiobits[0][2]
69
70 # self.put(ss, es, self.out_python, ['BITS', self.mdiobits])
71 self.put(ss, es, self.out_python, ['DATA', self.mdiodata])
72
73 # Bit annotations.
74 for bit in self.mdiobits:
75 self.put(bit[1], bit[2], self.out_ann, [1, ['%d' % bit[0]]])
76
77 # Error annotation if an error happened.
78 if self.error:
79 self.put(self.ss_bit, self.es_error, self.out_ann, [2, [self.error]])
80 return
81
82 op = 'READ' if self.operation else 'WRITE'
83
84 # Dataword annotations.
85 if self.ss_preamble != -1:
86 self.put(self.ss_preamble, self.ss_start, self.out_ann, [0, ['PREAMBLE']])
87 self.put(self.ss_start, self.ss_operation, self.out_ann, [0, ['START']])
88 self.put(self.ss_operation, self.ss_phy, self.out_ann, [0, [op]])
89 self.put(self.ss_phy, self.ss_reg, self.out_ann, [0, ['PHY: %d' % self.phy]])
90 self.put(self.ss_reg, self.ss_turnaround, self.out_ann, [0, ['REG: %d' % self.reg]])
91 self.put(self.ss_turnaround, self.ss_data, self.out_ann, [0, ['TURNAROUND']])
92 self.put(self.ss_data, self.es_data, self.out_ann, [0, ['DATA: %04X' % self.data]])
93
94 def reset_decoder_state(self):
95 self.mdiodata = 0
96 self.mdiobits = []
97 self.bitcount = 0
98 self.ss_preamble = -1
99 self.ss_start = -1
100 self.ss_operation = -1
101 self.ss_phy = -1
102 self.ss_reg = -1
103 self.ss_turnaround = -1
104 self.ss_data = -1
105 self.phy = 0
106 self.phy_bits = 0
107 self.reg = 0
108 self.reg_bits = 0
109 self.data = 0
110 self.data_bits = 0
111 self.state = 'PREAMBLE'
112 self.error = None
113
114 def parse_preamble(self, mdio):
115 if self.ss_preamble == -1:
116 self.ss_preamble = self.samplenum
117 if mdio != 1:
118 self.error = 'Invalid preamble: could not find 32 consecutive bits set to 1'
119 self.state = 'ERROR'
120 elif self.bitcount == 31:
121 self.state = 'START'
122
123 def parse_start(self, mdio):
124 if self.ss_start == -1:
125 if mdio != 0:
126 self.error = 'Invalid start bits: should be 01'
127 self.state = 'ERROR'
128 else:
129 self.ss_start = self.samplenum
130 else:
131 if mdio != 1:
132 self.error = 'Invalid start bits: should be 01'
133 self.state = 'ERROR'
134 else:
135 self.state = 'OPERATION'
136
137 def parse_operation(self, mdio):
138 if self.ss_operation == -1:
139 self.ss_operation = self.samplenum
140 self.operation = mdio
141 else:
142 if mdio == self.operation:
143 self.error = 'Invalid operation bits'
144 self.state = 'ERROR'
145 else:
146 self.state = 'PHY'
147
148 def parse_phy(self, mdio):
149 if self.ss_phy == -1:
150 self.ss_phy = self.samplenum
151 self.phy_bits += 1
152 self.phy |= mdio << (5 - self.phy_bits)
153 if self.phy_bits == 5:
154 self.state = 'REG'
155
156 def parse_reg(self, mdio):
157 if self.ss_reg == -1:
158 self.ss_reg = self.samplenum
159 self.reg_bits += 1
160 self.reg |= mdio << (5 - self.reg_bits)
161 if self.reg_bits == 5:
162 self.state = 'TURNAROUND'
163
164 def parse_turnaround(self, mdio):
165 if self.ss_turnaround == -1:
166 if self.operation == 0 and mdio != 1:
167 self.error = 'Invalid turnaround bits'
168 self.state = 'ERROR'
169 else:
170 self.ss_turnaround = self.samplenum
171 else:
172 if mdio != 0:
173 self.error = 'Invalid turnaround bits'
174 self.state = 'ERROR'
175 else:
176 self.state = 'DATA'
177
178 def parse_data(self, mdio):
179 if self.ss_data == -1:
180 self.ss_data = self.samplenum
181 self.data_bits += 1
182 self.data |= mdio << (16 - self.data_bits)
183 if self.data_bits == 16:
184 self.es_data = self.samplenum + int((self.samplenum - self.ss_data) / 15)
185 self.state = 'DONE'
186
187 def parse_error(self, mdio):
188 if self.bitcount == 63:
189 self.es_error = self.samplenum + int((self.samplenum - self.ss_bit) / 63)
190 self.state = 'DONE'
191
192 def handle_bit(self, mdio):
193 # If this is the first bit of a command, save its sample number.
194 if self.bitcount == 0:
195 self.ss_bit = self.samplenum
196 # No preamble?
197 if mdio == 0:
198 self.state = 'START'
199
200 # Guesstimate the endsample for this bit (can be overridden below).
201 es = self.samplenum
202 if self.bitcount > 0:
203 es += self.samplenum - self.mdiobits[0][1]
204
205 self.mdiobits.insert(0, [mdio, self.samplenum, es])
206
207 if self.bitcount > 0:
208 self.bitsamples = (self.samplenum - self.ss_bit) / self.bitcount
209 self.mdiobits[1][2] = self.samplenum
210
211 if self.state == 'PREAMBLE':
212 self.parse_preamble(mdio)
213 elif self.state == 'START':
214 self.parse_start(mdio)
215 elif self.state == 'OPERATION':
216 self.parse_operation(mdio)
217 elif self.state == 'PHY':
218 self.parse_phy(mdio)
219 elif self.state == 'REG':
220 self.parse_reg(mdio)
221 elif self.state == 'TURNAROUND':
222 self.parse_turnaround(mdio)
223 elif self.state == 'DATA':
224 self.parse_data(mdio)
225 elif self.state == 'ERROR':
226 self.parse_error(mdio)
227
228 self.bitcount += 1
229 if self.state == 'DONE':
230 self.putdata()
231 self.reset_decoder_state()
232
233 def find_mdc_edge(self, mdc, mdio):
234 # Output the current error annotation if the clock stopped running
235 if self.state == 'ERROR' and self.samplenum - self.clocksample > (1.5 * self.bitsamples):
236 self.es_error = self.clocksample + int((self.clocksample - self.ss_bit) / self.bitcount)
237 self.putdata()
238 self.reset_decoder_state()
239
240 # Ignore sample if the clock pin hasn't changed.
241 if mdc == self.oldmdc:
242 return
243
244 self.oldmdc = mdc
245
246 if mdc == 0: # Sample on rising clock edge.
247 return
248
249 # Found the correct clock edge, now get/handle the bit(s).
250 self.clocksample = self.samplenum
251 self.handle_bit(mdio)
252
253 def decode(self, ss, es, data):
254 for (self.samplenum, pins) in data:
255 # Ignore identical samples early on (for performance reasons).
256 if self.oldpins == pins:
257 continue
258 self.oldpins, (mdc, mdio) = pins, pins
259
260 self.find_mdc_edge(mdc, mdio)