X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=decoders%2Fspiflash%2Fpd.py;h=3d40ceb0663d424a3ff65f4cf7b0151e2491c5a8;hb=e33410d3f96db7bb6a2ed0e2540e0df17bf561b5;hp=0f4dd9b4a225574e0c330b68d97633f947f10764;hpb=c2446117b9758b14e328e4244e9787e5fb65f62b;p=libsigrokdecode.git diff --git a/decoders/spiflash/pd.py b/decoders/spiflash/pd.py index 0f4dd9b..3d40ceb 100644 --- a/decoders/spiflash/pd.py +++ b/decoders/spiflash/pd.py @@ -24,6 +24,19 @@ from .lists import * def cmd_annotation_classes(): return tuple([tuple([cmd[0].lower(), cmd[1]]) for cmd in cmds.values()]) +def decode_dual_bytes(sio0, sio1): + # Given a byte in SIO0 (MOSI) of even bits and a byte in + # SIO1 (MISO) of odd bits, return a tuple of two bytes. + def combine_byte(even, odd): + result = 0 + for bit in range(4): + if even & (1 << bit): + result |= 1 << (bit*2) + if odd & (1 << bit): + result |= 1 << ((bit*2) + 1) + return result + return (combine_byte(sio0 >> 4, sio1 >> 4), combine_byte(sio0, sio1)) + def decode_status_reg(data): # TODO: Additional per-bit(s) self.put() calls with correct start/end. @@ -56,7 +69,7 @@ class Decoder(srd.Decoder): longname = 'SPI flash chips' desc = 'xx25 series SPI (NOR) flash chip protocol.' license = 'gplv2+' - inputs = ['logic'] + inputs = ['spi'] outputs = ['spiflash'] annotations = cmd_annotation_classes() + ( ('bits', 'Bits'), @@ -71,9 +84,26 @@ class Decoder(srd.Decoder): options = ( {'id': 'chip', 'desc': 'Chip', 'default': tuple(chips.keys())[0], 'values': tuple(chips.keys())}, + {'id': 'format', 'desc': 'Data format', 'default': 'hex', + 'values': ('hex', 'ascii')}, ) - def __init__(self, **kwargs): + def __init__(self): + self.on_end_transaction = None + self.end_current_transaction() + + # Build dict mapping command keys to handler functions. Each + # command in 'cmds' (defined in lists.py) has a matching + # handler self.handle_. + def get_handler(cmd): + s = 'handle_%s' % cmds[cmd][0].lower().replace('/', '_') + return getattr(self, s) + self.cmd_handlers = dict((cmd, get_handler(cmd)) for cmd in cmds.keys()) + + def end_current_transaction(self): + if self.on_end_transaction is not None: # Callback for CS# transition. + self.on_end_transaction() + self.on_end_transaction = None self.state = None self.cmdstate = 1 self.addr = 0 @@ -88,7 +118,7 @@ class Decoder(srd.Decoder): self.put(self.ss, self.es, self.out_ann, data) def putb(self, data): - self.put(self.block_ss, self.block_es, self.out_ann, data) + self.put(self.ss_block, self.es_block, self.out_ann, data) def handle_wren(self, mosi, miso): self.putx([0, ['Command: %s' % cmds[self.state][1]]]) @@ -133,13 +163,8 @@ class Decoder(srd.Decoder): self.putx([3, ['Command: %s' % cmds[self.state][1]]]) elif self.cmdstate >= 2: # Bytes 2-x: Slave sends status register as long as master clocks. - if self.cmdstate <= 3: # TODO: While CS# asserted. - self.putx([24, ['Status register: 0x%02x' % miso]]) - self.putx([25, [decode_status_reg(miso)]]) - - if self.cmdstate == 3: # TODO: If CS# got de-asserted. - self.state = None - return + self.putx([24, ['Status register: 0x%02x' % miso]]) + self.putx([25, [decode_status_reg(miso)]]) self.cmdstate += 1 @@ -162,19 +187,10 @@ class Decoder(srd.Decoder): self.addr = 0 elif self.cmdstate >= 5: # Bytes 5-x: Master reads data bytes (until CS# de-asserted). - # TODO: For now we hardcode 256 bytes per READ command. - if self.cmdstate <= 256 + 4: # TODO: While CS# asserted. - self.data.append(miso) - # self.putx([0, ['New read byte: 0x%02x' % miso]]) - - if self.cmdstate == 256 + 4: # TODO: If CS# got de-asserted. - # s = ', '.join(map(hex, self.data)) - s = ''.join(map(chr, self.data)) - self.putx([24, ['Read data']]) - self.putx([25, ['Read data: %s' % s]]) - self.data = [] - self.state = None - return + if self.cmdstate == 5: + self.ss_block = self.ss + self.on_end_transaction = lambda: self.output_data_block('Read') + self.data.append(miso) self.cmdstate += 1 @@ -188,32 +204,38 @@ class Decoder(srd.Decoder): # Bytes 2/3/4: Master sends read address (24bits, MSB-first). self.putx([24, ['AD%d: 0x%02x' % (self.cmdstate - 1, mosi)]]) if self.cmdstate == 2: - self.block_ss = self.ss + self.ss_block = self.ss self.addr |= (mosi << ((4 - self.cmdstate) * 8)) elif self.cmdstate == 5: self.putx([24, ['Dummy byte: 0x%02x' % mosi]]) - self.block_es = self.es + self.es_block = self.es self.putb([5, ['Read address: 0x%06x' % self.addr]]) self.addr = 0 elif self.cmdstate >= 6: # Bytes 6-x: Master reads data bytes (until CS# de-asserted). - # TODO: For now we hardcode 32 bytes per FAST READ command. if self.cmdstate == 6: - self.block_ss = self.ss - if self.cmdstate <= 32 + 5: # TODO: While CS# asserted. - self.data.append(miso) - if self.cmdstate == 32 + 5: # TODO: If CS# got de-asserted. - self.block_es = self.es - s = ' '.join([hex(b)[2:] for b in self.data]) - self.putb([25, ['Read data: %s' % s]]) - self.data = [] - self.state = None - return + self.ss_block = self.ss + self.on_end_transaction = lambda: self.output_data_block('Read') + self.data.append(miso) self.cmdstate += 1 def handle_2read(self, mosi, miso): - pass # TODO + # Fast read dual I/O: Same as fast read, but all data + # after the command is sent via two I/O pins. + # MOSI = SIO0 = even bits, MISO = SIO1 = odd bits. + # Recombine the bytes and pass them up to the handle_fast_read command. + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.putx([5, ['Command: %s' % cmds[self.state][1]]]) + self.cmdstate = 2 + else: + # Dual I/O mode. + a, b = decode_dual_bytes(mosi, miso) + # Pass same byte in as both MISO & MOSI, parser state determines + # which one it cares about. + self.handle_fast_read(a, a) + self.handle_fast_read(b, b) # TODO: Warn/abort if we don't see the necessary amount of bytes. # TODO: Warn if WREN was not seen before. @@ -266,19 +288,10 @@ class Decoder(srd.Decoder): self.addr = 0 elif self.cmdstate >= 5: # Bytes 5-x: Master sends data bytes (until CS# de-asserted). - # TODO: For now we hardcode 256 bytes per page / PP command. - if self.cmdstate <= 256 + 4: # TODO: While CS# asserted. - self.data.append(mosi) - # self.putx([0, ['New data byte: 0x%02x' % mosi]]) - - if self.cmdstate == 256 + 4: # TODO: If CS# got de-asserted. - # s = ', '.join(map(hex, self.data)) - s = ''.join(map(chr, self.data)) - self.putx([24, ['Page data']]) - self.putx([25, ['Page data: %s' % s]]) - self.data = [] - self.state = None - return + if self.cmdstate == 5: + self.ss_block = self.ss + self.on_end_transaction = lambda: self.output_data_block('Page data') + self.data.append(mosi) self.cmdstate += 1 @@ -289,7 +302,20 @@ class Decoder(srd.Decoder): pass # TODO def handle_rdp_res(self, mosi, miso): - pass # TODO + if self.cmdstate == 1: + # Byte 1: Master sends command ID. + self.ss_block = self.ss + self.putx([16, ['Command: %s' % cmds[self.state][1]]]) + elif self.cmdstate in (2, 3, 4): + # Bytes 2/3/4: Master sends three dummy bytes. + self.putx([24, ['Dummy byte: %02x' % mosi]]) + elif self.cmdstate == 5: + # Byte 5: Slave sends device ID. + self.ids = [miso] + self.putx([24, ['Device: Macronix %s' % device_name[self.ids[0]]]]) + self.state = None + + self.cmdstate += 1 def handle_rems(self, mosi, miso): if self.cmdstate == 1: @@ -346,34 +372,35 @@ class Decoder(srd.Decoder): def handle_dsry(self, mosi, miso): pass # TODO - def decode(self, ss, es, data): + def output_data_block(self, label): + # Print accumulated block of data + # (called on CS# de-assert via self.on_end_transaction callback). + self.es_block = self.es # Ends on the CS# de-assert sample. + if self.options['format'] == 'hex': + s = ' '.join([('%02x' % b) for b in self.data]) + else: + s = ''.join(map(chr, self.data)) + self.putb([25, ['%s %d bytes: %s' % (label, len(self.data), s)]]) + def decode(self, ss, es, data): ptype, mosi, miso = data - # if ptype == 'DATA': - # self.putx([0, ['MOSI: 0x%02x, MISO: 0x%02x' % (mosi, miso)]]) + self.ss, self.es = ss, es - # if ptype == 'CS-CHANGE': - # if mosi == 1 and miso == 0: - # self.putx([0, ['Asserting CS#']]) - # elif mosi == 0 and miso == 1: - # self.putx([0, ['De-asserting CS#']]) + if ptype == 'CS-CHANGE': + self.end_current_transaction() if ptype != 'DATA': return - self.ss, self.es = ss, es - # If we encountered a known chip command, enter the resp. state. if self.state is None: self.state = mosi self.cmdstate = 1 # Handle commands. - if self.state in cmds: - s = 'handle_%s' % cmds[self.state][0].lower().replace('/', '_') - handle_reg = getattr(self, s) - handle_reg(mosi, miso) - else: + try: + self.cmd_handlers[self.state](mosi, miso) + except KeyError: self.putx([24, ['Unknown command: 0x%02x' % mosi]]) self.state = None