Hi Sigrokkers,
I added some features to the spiflash decoder that might be
useful. Patches attached:
- Handle variable-length transactions by adding a callback on CS#
release.
- Decode Fast Read Dual I/O commands. (Similar approach could be used
for Fast Read Dual Output but I don't have a suitable capture to
verify against.)
- Small tweak to build a dictionary once instead of on every SPI event.
There's also this capture featuring Dual I/O commands here, if that's
of interest for the captures repo:
https://www.dropbox.com/s/rt0o69nesvzkzpq/dualioreads.sr?dl=0
Cheers,
Angus
>From d1428304030bc7d7a0766ed39bb8ff6f611111a2 Mon Sep 17 00:00:00 2001
From: Angus Gratton <g...@projectgus.com>
Date: Sun, 22 May 2016 11:42:52 +1000
Subject: [PATCH 1/3] spiflash decoder: Handle CS# transitions, allow
variable-length transfers
---
decoders/spiflash/pd.py | 80 +++++++++++++++++++------------------------------
1 file changed, 30 insertions(+), 50 deletions(-)
diff --git a/decoders/spiflash/pd.py b/decoders/spiflash/pd.py
index 1e3b916..83abf82 100644
--- a/decoders/spiflash/pd.py
+++ b/decoders/spiflash/pd.py
@@ -74,6 +74,13 @@ class Decoder(srd.Decoder):
)
def __init__(self):
+ self.on_end_transaction = None
+ self.end_current_transaction()
+
+ 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
@@ -133,13 +140,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 +164,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.block_ss = self.ss
+ self.on_end_transaction = lambda: self.output_data_block("Read")
+ self.data.append(miso)
self.cmdstate += 1
@@ -197,18 +190,10 @@ class Decoder(srd.Decoder):
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.on_end_transaction = lambda: self.output_block("Read")
+ self.data.append(miso)
self.cmdstate += 1
@@ -266,19 +251,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.block_ss = self.ss
+ self.on_end_transaction = lambda: self.output_data_block("Page data")
+ self.data.append(mosi)
self.cmdstate += 1
@@ -346,24 +322,28 @@ class Decoder(srd.Decoder):
def handle_dsry(self, mosi, miso):
pass # TODO
+ def output_data_block(self, label):
+ """ Print accumulated block of data
+ (called on CS# de-assert via self.on_end_transaction callback)
+ """
+ self.block_es = self.es # ends on the CS# de-assert sample
+ s = ' '.join([("%02x"%b) for b in 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
--
2.8.3
>From 11826641debdadd1301431253a5ac6d674b14b32 Mon Sep 17 00:00:00 2001
From: Angus Gratton <g...@projectgus.com>
Date: Sun, 22 May 2016 11:43:45 +1000
Subject: [PATCH 2/3] spiflash decoder: Handle "Fast Read Dual I/O"
---
decoders/spiflash/pd.py | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/decoders/spiflash/pd.py b/decoders/spiflash/pd.py
index 83abf82..b8b29ad 100644
--- a/decoders/spiflash/pd.py
+++ b/decoders/spiflash/pd.py
@@ -24,6 +24,20 @@ 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.
@@ -192,13 +206,26 @@ class Decoder(srd.Decoder):
# Bytes 6-x: Master reads data bytes (until CS# de-asserted).
if self.cmdstate == 6:
self.block_ss = self.ss
- self.on_end_transaction = lambda: self.output_block("Read")
+ 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.
--
2.8.3
>From 70c005d97a7add6d921b303a887f149bdc6ab5c6 Mon Sep 17 00:00:00 2001
From: Angus Gratton <g...@projectgus.com>
Date: Sun, 22 May 2016 11:47:57 +1000
Subject: [PATCH 3/3] spiflash decoder: Perf tweak: Build handler lookup table
once per decoder
---
decoders/spiflash/pd.py | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/decoders/spiflash/pd.py b/decoders/spiflash/pd.py
index b8b29ad..e501037 100644
--- a/decoders/spiflash/pd.py
+++ b/decoders/spiflash/pd.py
@@ -91,6 +91,15 @@ class Decoder(srd.Decoder):
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_<shortname>
+ 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()
@@ -377,10 +386,8 @@ class Decoder(srd.Decoder):
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
--
2.8.3
------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic
patterns at an interface-level. Reveals which users, apps, and protocols are
consuming the most bandwidth. Provides multi-vendor support for NetFlow,
J-Flow, sFlow and other flows. Make informed decisions using capacity
planning reports. https://ad.doubleclick.net/ddm/clk/305295220;132659582;e
_______________________________________________
sigrok-devel mailing list
sigrok-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sigrok-devel