2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
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.
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.
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
21 import sigrokdecode as srd
23 class Decoder(srd.Decoder):
27 longname = 'Management Data Input/Output'
28 desc = 'Half-duplex sync serial bus for MII management between MAC and PHY.'
33 {'id': 'mdc', 'name': 'MDC', 'desc': 'Clock'},
34 {'id': 'mdio', 'name': 'MDIO', 'desc': 'Data'},
37 ('mdio-data', 'MDIO data'),
38 ('mdio-bits', 'MDIO bits'),
39 ('errors', 'Human-readable errors'),
42 ('mdio-data', 'MDIO data', (0,)),
43 ('mdio-bits', 'MDIO bits', (1,)),
44 ('other', 'Other', (2,)),
52 self.reset_decoder_state()
55 self.out_python = self.register(srd.OUTPUT_PYTHON)
56 self.out_ann = self.register(srd.OUTPUT_ANN)
59 self.put(self.ss_block, self.samplenum, self.out_ann, data)
61 def putbit(self, mdio, start, stop):
63 self.put(start, stop, self.out_ann, [1, ['%d' % mdio]])
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]
70 # self.put(ss, es, self.out_python, ['BITS', self.mdiobits])
71 self.put(ss, es, self.out_python, ['DATA', self.mdiodata])
74 for bit in self.mdiobits:
75 self.put(bit[1], bit[2], self.out_ann, [1, ['%d' % bit[0]]])
77 # Error annotation if an error happened.
79 self.put(self.ss_bit, self.es_error, self.out_ann, [2, [self.error]])
82 op = 'READ' if self.operation else 'WRITE'
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]])
94 def reset_decoder_state(self):
100 self.ss_operation = -1
103 self.ss_turnaround = -1
111 self.state = 'PREAMBLE'
114 def parse_preamble(self, mdio):
115 if self.ss_preamble == -1:
116 self.ss_preamble = self.samplenum
118 self.error = 'Invalid preamble: could not find 32 consecutive bits set to 1'
120 elif self.bitcount == 31:
123 def parse_start(self, mdio):
124 if self.ss_start == -1:
126 self.error = 'Invalid start bits: should be 01'
129 self.ss_start = self.samplenum
132 self.error = 'Invalid start bits: should be 01'
135 self.state = 'OPERATION'
137 def parse_operation(self, mdio):
138 if self.ss_operation == -1:
139 self.ss_operation = self.samplenum
140 self.operation = mdio
142 if mdio == self.operation:
143 self.error = 'Invalid operation bits'
148 def parse_phy(self, mdio):
149 if self.ss_phy == -1:
150 self.ss_phy = self.samplenum
152 self.phy |= mdio << (5 - self.phy_bits)
153 if self.phy_bits == 5:
156 def parse_reg(self, mdio):
157 if self.ss_reg == -1:
158 self.ss_reg = self.samplenum
160 self.reg |= mdio << (5 - self.reg_bits)
161 if self.reg_bits == 5:
162 self.state = 'TURNAROUND'
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'
170 self.ss_turnaround = self.samplenum
173 self.error = 'Invalid turnaround bits'
178 def parse_data(self, mdio):
179 if self.ss_data == -1:
180 self.ss_data = self.samplenum
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)
187 def parse_error(self, mdio):
188 if self.bitcount == 63:
189 self.es_error = self.samplenum + int((self.samplenum - self.ss_bit) / 63)
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
200 # Guesstimate the endsample for this bit (can be overridden below).
202 if self.bitcount > 0:
203 es += self.samplenum - self.mdiobits[0][1]
205 self.mdiobits.insert(0, [mdio, self.samplenum, es])
207 if self.bitcount > 0:
208 self.bitsamples = (self.samplenum - self.ss_bit) / self.bitcount
209 self.mdiobits[1][2] = self.samplenum
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':
219 elif self.state == 'REG':
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)
229 if self.state == 'DONE':
231 self.reset_decoder_state()
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)
238 self.reset_decoder_state()
240 # Ignore sample if the clock pin hasn't changed.
241 if mdc == self.oldmdc:
246 if mdc == 0: # Sample on rising clock edge.
249 # Found the correct clock edge, now get/handle the bit(s).
250 self.clocksample = self.samplenum
251 self.handle_bit(mdio)
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:
258 self.oldpins, (mdc, mdio) = pins, pins
260 self.find_mdc_edge(mdc, mdio)